PageRenderTime 122ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 1ms

/formprocessor.php

https://bitbucket.org/dmptool/dmp2brochure
PHP | 13406 lines | 9591 code | 698 blank | 3117 comment | 673 complexity | 617c934ab1b7e9aacfa1aee055a0dfbb MD5 | raw file
  1. <?php
  2. $FM_VERS = "8.36"; // script version
  3. /* ex:set ts=4 sw=4 et:
  4. * FormMail PHP script from Tectite.com. This script requires PHP 4 or later.
  5. * Copyright (c) 2001-2012 Root Software and Open Concepts (Vic) Pty Ltd
  6. * (ABN 12 130 429 248), Melbourne, Australia.
  7. * This script is free for all use as described in the "Copying and Use" and
  8. * "Warranty and Disclaimer" sections below.
  9. *
  10. * Visit us at http://www.tectite.com/ for updates and more information.
  11. *
  12. *** If you use Tectite FormMail, please support its development and other
  13. *** freeware products by putting the following link on your website:
  14. *** Visit www.tectite.com for free <a href="http://www.tectite.com/">FormMail</a>.
  15. *
  16. * Author: Russell Robinson, 2nd October 2001
  17. *
  18. * Read This First
  19. * ~~~~~~~~~~~~~~~
  20. * This script is very well documented and quite large! It looks daunting,
  21. * but really isn't.
  22. * If you have experience with PHP or other scripting languages,
  23. * here's what you *need* to read:
  24. * - Configuration (TARGET_EMAIL & DEF_ALERT)
  25. * - Creating Forms
  26. * That's it! (Alternatively, just read the Quick Start and/or
  27. * Quicker Start section below).
  28. * Full configuration documentation is here:
  29. * http://www.tectite.com/fmdoc/index.php
  30. *
  31. * NOTE: do not read or modify this script or any PHP script
  32. * with DreamWeaver or FrontPage!
  33. * Many versions of those programs silently corrupt PHP scripts.
  34. *
  35. * Purpose:
  36. * ~~~~~~~~
  37. * To accept information from an HTML form via HTTP and mail it to recipients.
  38. *
  39. * What does this PHP script do?
  40. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  41. * On your web site, you may have one or more HTML forms that accept
  42. * information from people visiting your website. Your aim is for your
  43. * website to email that information to you and/or add it to a database.
  44. * FormMail performs those functions.
  45. *
  46. * Quick Start
  47. * ~~~~~~~~~~~
  48. * 1. Edit this file and set TARGET_EMAIL for your requirements (near
  49. * line 256 in this file - replace "yourhost\.com" with your mail server's
  50. * name). We also strongly recommend you set DEF_ALERT (the next
  51. * configuration below TARGET_EMAIL).
  52. * 2. Install this file as formmail.php (or other name ending in .php)
  53. * on your web server.
  54. * Test alerts by using your browser to open a URL to the script:
  55. * http://www.yourhost.com/formmail.php?testalert=1
  56. * Alerts are the only way FormMail can tell you the details of
  57. * errors or faults.
  58. * 3. Create an HTML form and:
  59. * - specify a hidden field called "recipients" with the email address
  60. * of the person to receive the form's results.
  61. * - in the your form tag set the action attribute to
  62. * the formmail.php you uploaded to your web server
  63. *
  64. * Once you have FormMail working, you may be interested in some advanced
  65. * usage and features. We have HOW-TO guides at www.tectite.com which
  66. * describe many of the advanced processing you can do with FormMail.
  67. * http://www.tectite.com/fmhowto/guides.php
  68. *
  69. * Quicker Start
  70. * ~~~~~~~~~~~~~
  71. * Use the FormMail Configuration Wizard here:
  72. * http://www.tectite.com/wizards/fmconf.php
  73. * By answering a few questions you'll get a configured FormMail and
  74. * a sample HTML form ready to upload and use on your server.
  75. *
  76. * Features
  77. * ~~~~~~~~
  78. * For a list of features go to: http://www.tectite.com/formmailpage.php
  79. *
  80. * Security
  81. * ~~~~~~~~
  82. * Security is the primary concern in accepting data from your website
  83. * visitors.
  84. * Tectite FormMail has several security features designed into it. Note,
  85. * however, it requires configuration for your particular web site.
  86. *
  87. * Configuration
  88. * ~~~~~~~~~~~~~
  89. * To configure this script, go to the section titled "CONFIGURATION"
  90. * (after reading the legal stuff below).
  91. *
  92. * There is only one mandatory setting: TARGET_EMAIL
  93. * and one strongly recommended setting: DEF_ALERT
  94. *
  95. * Full configuration information is available here:
  96. * http://www.tectite.com/fmdoc/index.php
  97. *
  98. * Creating Forms
  99. * ~~~~~~~~~~~~~~
  100. * Go to this URL to learn how to write HTML forms for use with
  101. * Tectite FormMail: http://www.tectite.com/fmdoc/creating_forms.php
  102. *
  103. * Copying and Use (Software License)
  104. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  105. * Tectite FormMail is provided free of charge and may be freely distributed
  106. * and used provided that you:
  107. * 1. keep this header, including copyright and comments,
  108. * in place and unmodified; and,
  109. * 2. do not charge a fee for distributing it, without an agreement
  110. * in writing with Root Software allowing you to do so; and,
  111. * 3. if you modify FormMail before distributing it, you clearly
  112. * identify:
  113. * a) who you are
  114. * b) how to contact you
  115. * c) what changes you have made
  116. * d) why you have made those changes.
  117. *
  118. * By using any of our products, including this script, you are
  119. * agreeing to our standard Terms and Conditions, available here:
  120. * http://www.tectite.com/TermsAndConditions.pdf
  121. *
  122. * This is free software and the Software License shown above
  123. * is to be read in conjunction with our standard Terms and Conditions.
  124. *
  125. * Warranty and Disclaimer
  126. * ~~~~~~~~~~~~~~~~~~~~~~~
  127. * Tectite FormMail is provided free-of-charge and with ABSOLUTELY NO WARRANTY.
  128. * It has not been verified for use in critical applications, including,
  129. * but not limited to, medicine, defense, aircraft, space exploration,
  130. * or any other potentially dangerous activity.
  131. *
  132. * By using Tectite FormMail you agree to indemnify Root Software and
  133. * Open Concepts (Vic) Pty Ltd, their agents, employees, directors and
  134. * associated companies and businesses from any liability whatsoever.
  135. *
  136. * We still care
  137. * ~~~~~~~~~~~~~
  138. * If you find a bug or fault in FormMail, please report it to us.
  139. * We will respond to your report and make endeavours to rectify any
  140. * faults you've detected as soon as possible.
  141. *
  142. * To contact us please register on our forums at:
  143. * http://www.tectite.com/vbforums/
  144. * or view our contact information:
  145. * http://www.tectite.com/contacts.php
  146. *
  147. * Version History
  148. * ~~~~~~~~~~~~~~~
  149. * Near the top of this file, you'll find its version. The version
  150. * line looks like this:
  151. * $FM_VERS = "N.MM"; /* script version ...
  152. *
  153. * The version history used to be located within this file. However,
  154. * starting with Version 8.00 we've moved it...
  155. *
  156. * You can read the complete version history of FormMail on our
  157. * main website here:
  158. * http://www.tectite.com/fmdoc/version_history.php
  159. */
  160. FMDebug('Submission to: '.(isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '').' from: '.(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
  161. if (isset($_SERVER['REQUEST_METHOD']) && strtoupper($_SERVER['REQUEST_METHOD']) === 'OPTIONS')
  162. {
  163. FMDebug('CORS OPTIONS request');
  164. CORS_Response();
  165. exit;
  166. }
  167. //
  168. // Capture the current date and time, for various purposes.
  169. //
  170. $lNow = time();
  171. ini_set('track_errors',1); // enable $php_errormsg
  172. $aAlertInfo = array();
  173. $aPHPVERSION = array();
  174. $sLangID = ""; // the language ID
  175. $aMessages = array(); // all FormMail messages in the appropriate
  176. // language
  177. $bUseOldVars = IsOldVersion($aPHPVERSION);
  178. if (!IsPHPAtLeast("5.3.0"))
  179. //
  180. // disable this silly setting (usually not enabled)
  181. // it's also deprecated from PHP version 5.3.0
  182. //
  183. set_magic_quotes_runtime(0);
  184. //
  185. // seed the random number generate if not version 4.2.0 or later
  186. //
  187. if (!IsPHPAtLeast("4.2.0"))
  188. mt_srand(time());
  189. //
  190. // we set references to the appropriate arrays to handle PHP version differences
  191. // Session vars are selected after we start the session.
  192. //
  193. if ($bUseOldVars)
  194. {
  195. $aServerVars = &$HTTP_SERVER_VARS;
  196. $aGetVars = &$HTTP_GET_VARS;
  197. $aFormVars = &$HTTP_POST_VARS;
  198. $aFileVars = &$HTTP_POST_FILES;
  199. $aEnvVars = &$HTTP_ENV_VARS;
  200. }
  201. else
  202. {
  203. $aServerVars = &$_SERVER;
  204. $aGetVars = &$_GET;
  205. $aFormVars = &$_POST;
  206. $aFileVars = &$_FILES;
  207. $aEnvVars = &$_ENV;
  208. }
  209. $bIsGetMethod = false;
  210. $bHasGetData = false;
  211. if (!isset($REAL_DOCUMENT_ROOT))
  212. SetRealDocumentRoot();
  213. if (isset($aServerVars['SERVER_PORT']))
  214. $SCHEME = ($aServerVars['SERVER_PORT'] == 80) ? "http://" : "https://";
  215. else
  216. $SCHEME = "";
  217. if (isset($aServerVars['SERVER_NAME']) && $aServerVars['SERVER_NAME'] !== "")
  218. $SERVER = $aServerVars['SERVER_NAME'];
  219. elseif (isset($aServerVars['SERVER_ADDR']) && $aServerVars['SERVER_ADDR'] !== "")
  220. $SERVER = $aServerVars['SERVER_ADDR'];
  221. else
  222. $SERVER = "";
  223. /*
  224. * Load an optional include file before the configuration.
  225. * You can use this to set variables that can be used in the
  226. * configuration section.
  227. */
  228. @include("formmail-preconfig.inc.php");
  229. /*****************************************************************************/
  230. /* CONFIGURATION (do not alter this line in any way!!!) */
  231. /*****************************************************************************
  232. * This is the *only* place where you need to modify things to use formmail.php
  233. * on your particular system. This section finishes at "END OF CONFIGURATION".
  234. * Help for all settings can be found on our website:
  235. * http://www.tectite.com/fmdoc/index.php
  236. *
  237. * Also, above each setting is a direct URL to the help information for the
  238. * setting.
  239. *****************************************************************************/
  240. /* Help: http://www.tectite.com/fmdoc/email_name.php */
  241. define("EMAIL_NAME","^[-a-z0-9.]+"); // the '^' is an important security feature!
  242. /* Help: http://www.tectite.com/fmdoc/target_email.php */
  243. $TARGET_EMAIL = array("^uc3@ucop\.edu$");
  244. // $TARGET_EMAIL = array("^joel\.hagedorn@ucop\.edu$");
  245. /* Help: http://www.tectite.com/fmdoc/def_alert.php */
  246. define("DEF_ALERT","joel.hagedorn@ucop.edu");
  247. /* Help: http://www.tectite.com/fmdoc/site_domain.php */
  248. $SITE_DOMAIN = ""; // your website domain name
  249. /* Help: http://www.tectite.com/fmdoc/set_real_document_root.php */
  250. $SET_REAL_DOCUMENT_ROOT = ""; // overrides the value set by SetRealDocumentRoot function
  251. //
  252. // override $REAL_DOCUMENT_ROOT from the $SET_REAL_DOCUMENT_ROOT value (if any)
  253. // Do not alter the following code (next 3 lines)!
  254. //
  255. if (isset($SET_REAL_DOCUMENT_ROOT) && $SET_REAL_DOCUMENT_ROOT !== "")
  256. $REAL_DOCUMENT_ROOT = $SET_REAL_DOCUMENT_ROOT;
  257. /* Help: http://www.tectite.com/fmdoc/config_check.php */
  258. $CONFIG_CHECK = array("TARGET_EMAIL");
  259. /* Help: http://www.tectite.com/fmdoc/at_mangle.php */
  260. define("AT_MANGLE","ATT");
  261. /* Help: http://www.tectite.com/fmdoc/target_urls.php */
  262. $TARGET_URLS = array(); // default; no URLs allowed
  263. /* Help: http://www.tectite.com/fmdoc/head_crlf.php */
  264. define("HEAD_CRLF","\r\n");
  265. /* Help: http://www.tectite.com/fmdoc/body_lf.php */
  266. define("BODY_LF","\r\n"); // the new default: use this for CR+LF
  267. //define("BODY_LF","\n"); // the old default: just LF
  268. /* Help: http://www.tectite.com/fmdoc/from_user.php */
  269. $FROM_USER = ""; // the default - setting not used
  270. /* Help: http://www.tectite.com/fmdoc/sendmail_f_option.php */
  271. define("SENDMAIL_F_OPTION",false);
  272. define("SENDMAIL_F_OPTION_LINE",__LINE__-1); // don't modify this line!
  273. /* Help: http://www.tectite.com/fmdoc/fixed_sender.php */
  274. $FIXED_SENDER = "";
  275. /* Help: http://www.tectite.com/fmdoc/set_sender_from_email.php */
  276. define("SET_SENDER_FROM_EMAIL",false);
  277. /* Help: http://www.tectite.com/fmdoc/ini_set_from.php */
  278. define("INI_SET_FROM",false);
  279. /* Help: http://www.tectite.com/fmdoc/logdir.php */
  280. $LOGDIR = ""; // directory for log files; empty string to
  281. // disallow log files
  282. /* Help: http://www.tectite.com/fmdoc/autorespondlog.php */
  283. $AUTORESPONDLOG = ""; // file name in $LOGDIR for the auto responder
  284. // log; empty string for no auto responder log
  285. /* Help: http://www.tectite.com/fmdoc/csv_file_settings.php */
  286. $CSVDIR = ""; // directory for csv files; empty string to
  287. // disallow csv files
  288. $CSVSEP = ","; // comma separator between fields (columns)
  289. $CSVINTSEP = ";"; // semicolon is the separator for fields (columns)
  290. // with multiple values (checkboxes, etc.)
  291. $CSVQUOTE = '"'; // all fields in the CSV are quoted with this character;
  292. // default is double quote. You can change it to
  293. // single quote or leave it empty for no quotes.
  294. //$CSVQUOTE = "'"; // use this if you want single quotes
  295. $CSVOPEN = ""; // set to "b" to force line terminations to be
  296. // kept as $CSVLINE setting below, regardless of
  297. // operating system. Keep as empty string and
  298. // leave $CSVLINE unchanged, to get text file
  299. // terminations for your server's operating system.
  300. // (Line feed on UNIX, carriage-return line feed on Windows).
  301. $CSVLINE = "\n"; // line termination for CSV files. The default is
  302. // a single line feed, which may be modified for your
  303. // server's operating system. If you want to change
  304. // this value, you *must* set $CSVOPEN = "b".
  305. /* Help: http://www.tectite.com/fmdoc/templatedir.php */
  306. $TEMPLATEDIR = ""; // directory for template files; empty string
  307. // if you don't have any templates
  308. /* Help: http://www.tectite.com/fmdoc/templateurl.php */
  309. $TEMPLATEURL = ""; // default; no template URL
  310. /* Help: http://www.tectite.com/fmdoc/multiformdir.php */
  311. $MULTIFORMDIR = ""; // directory for multi-form template files; empty string
  312. // if you're not using multi-forms
  313. /* Help: http://www.tectite.com/fmdoc/multiformurl.php */
  314. $MULTIFORMURL = ""; // default; no multi-forms templates URL
  315. /* Help: http://www.tectite.com/fmdoc/text_subs.php */
  316. $TEXT_SUBS = array(
  317. array("srch"=>"/\\\\r\\\\n/","repl"=>"\r\n",),
  318. array("srch"=>"/\\\\n/","repl"=>"\n",),
  319. array("srch"=>"/\\\\t/","repl"=>"\t",),
  320. array("srch"=>"/\\[NL\\]/","repl"=>"\n",),
  321. array("srch"=>"/\\[TAB\\]/","repl"=>"\t",),
  322. array("srch"=>"/\\[NBSP\\]/","repl"=>"&nbsp;",),
  323. array("srch"=>"/\\[DQUOT\\]/","repl"=>'"',),
  324. array("srch"=>"/\\[SQUOT\\]/","repl"=>"'",),
  325. array("srch"=>"/\\[COLON\\]/","repl"=>":",),
  326. array("srch"=>"/\\[SLOSH\\]/","repl"=>"\\",),
  327. array("srch"=>"/\\[OPCURL\\]/","repl"=>"{",),
  328. array("srch"=>"/\\[CLCURL\\]/","repl"=>"}",),
  329. array("srch"=>"/(on[a-z]*|href|src)\\s*=\\s*/i","repl"=>""),/* strip html attributes that could be unsafe */
  330. array("srch"=>"/<\\s*(table|tr|td|th|p|ul|ol|li|b|i|u|strong|pre|h[1-6]|em|dl|dd|dt|hr|span|br)(\\b[^>]*?)>/i","repl"=>"<\$1\$2>",),
  331. array("srch"=>"#<\\s*/\\s*(table|tr|td|th|p|ul|ol|li|b|i|u|strong|pre|h[1-6]|em|dl|dd|dt|hr|span|br)\\s*>#i","repl"=>"</\$1>",),
  332. );
  333. /* Help: http://www.tectite.com/fmdoc/authentication_settings.php */
  334. $AUTHENTICATE = "";
  335. //$AUTHENTICATE = "Basic cnVzc2VsbHI6dGVzdA=="; // example
  336. $AUTH_USER = "";
  337. $AUTH_PW = "";
  338. /* Help: http://www.tectite.com/fmdoc/form_ini_file.php */
  339. $FORM_INI_FILE = "";
  340. /* Help: http://www.tectite.com/fmdoc/moduledir.php */
  341. $MODULEDIR = ".";
  342. /* Help: http://www.tectite.com/fmdoc/fmcompute.php */
  343. $FMCOMPUTE = "fmcompute.php";
  344. /* Help: http://www.tectite.com/fmdoc/fmgeoip.php */
  345. $FMGEOIP = "fmgeoip.php";
  346. /* Help: http://www.tectite.com/fmdoc/advanced_templates.php */
  347. define("ADVANCED_TEMPLATES",false); // set to true for advanced templates
  348. /* Help: http://www.tectite.com/fmdoc/limited_import.php */
  349. define("LIMITED_IMPORT",true); // set to true if your database cannot
  350. // handle escaped quotes or newlines within
  351. // imported data. Microsoft Access is one
  352. // example.
  353. /* Help: http://www.tectite.com/fmdoc/valid_env.php */
  354. $VALID_ENV = array('HTTP_REFERER','REMOTE_HOST','REMOTE_ADDR','REMOTE_USER',
  355. 'HTTP_USER_AGENT');
  356. /* Help: http://www.tectite.com/fmdoc/fileuploads.php */
  357. define("FILEUPLOADS",false); // set to true to allow file attachments
  358. /* Help: http://www.tectite.com/fmdoc/max_file_upload_size.php */
  359. define("MAX_FILE_UPLOAD_SIZE",0); // default of 0 means that other software
  360. // controls the maximum file upload size
  361. // (FormMail doesn't test the file size)
  362. /* Help: http://www.tectite.com/fmdoc/file_repository.php */
  363. $FILE_REPOSITORY = "";
  364. /* Help: http://www.tectite.com/fmdoc/file_mode.php */
  365. define("FILE_MODE",0664); // always precede with 0 to specify octal!
  366. /* Help: http://www.tectite.com/fmdoc/file_overwrite.php */
  367. define("FILE_OVERWRITE",true);
  368. /* Help: http://www.tectite.com/fmdoc/next_num_file.php */
  369. $NEXT_NUM_FILE = "";
  370. /* Help: http://www.tectite.com/fmdoc/put_data_in_url.php */
  371. define("PUT_DATA_IN_URL",true); // set to true to place data in the URL
  372. // for bad_url redirects
  373. /* Help: http://www.tectite.com/fmdoc/allow_get_method.php */
  374. $ALLOW_GET_METHOD = false;
  375. /* Help: http://www.tectite.com/fmdoc/db_see_input.php */
  376. define("DB_SEE_INPUT",false); // set to true to just see the input values
  377. /* Help: http://www.tectite.com/fmdoc/db_see_ini.php */
  378. define("DB_SEE_INI",false); // set to true to just see the ini file
  379. /* Help: http://www.tectite.com/fmdoc/maxstring.php */
  380. define("MAXSTRING",1024); // maximum string length for a value
  381. /* Help: http://www.tectite.com/fmdoc/require_captcha.php */
  382. $REQUIRE_CAPTCHA = ""; // set to a message string if your forms
  383. // must provide a CAPTCHA string
  384. /* Help: http://www.tectite.com/fmdoc/recaptcha_private_key.php */
  385. $RECAPTCHA_PRIVATE_KEY = "";
  386. /* Help: http://www.tectite.com/fmdoc/bshowmesgnumbers.php */
  387. $bShowMesgNumbers = false;
  388. /* Help: http://www.tectite.com/fmdoc/filters.php */
  389. /* Note for Tectite personnel: the upgrade Wizard will merge new values
  390. * but be careful of $var usage and quoting in new entries.
  391. */
  392. $FILTERS = array("encode"=>"$REAL_DOCUMENT_ROOT/cgi-bin/fmencoder -kpubkey.txt",
  393. "null"=>"null",
  394. "csv"=>"csv");
  395. /* Help: http://www.tectite.com/fmdoc/socket_filters.php */
  396. $SOCKET_FILTERS = array(
  397. "httpencode"=>array("site"=>"YourSiteHere",
  398. "port"=>80,
  399. "path"=>"/cgi-bin/fmencoder",
  400. "params"=>array(array("name"=>"key",
  401. "file"=>"$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt"))),
  402. "sslencode"=>array("site"=>"ssl://YourSecureSiteHere",
  403. "port"=>443,
  404. "path"=>"/cgi-bin/fmencoder",
  405. "params"=>array(array("name"=>"key",
  406. "file"=>"$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt"))),
  407. );
  408. /* Help: http://www.tectite.com/fmdoc/filter_attribs.php */
  409. $FILTER_ATTRIBS = array("encode"=>"Strips,MIME=application/vnd.fmencoded,Encrypts",
  410. "httpencode"=>"Strips,MIME=application/vnd.fmencoded,Encrypts",
  411. "sslencode"=>"Strips,MIME=application/vnd.fmencoded,Encrypts",
  412. "csv"=>"Strips,MIME=text/csv",);
  413. /* Help: http://www.tectite.com/fmdoc/check_for_new_version.php */
  414. define("CHECK_FOR_NEW_VERSION",true);
  415. define("CHECK_DAYS",30);
  416. /* Help: http://www.tectite.com/fmdoc/scratch_pad.php */
  417. $SCRATCH_PAD = "";
  418. /* Help: http://www.tectite.com/fmdoc/cleanup_time.php */
  419. $CLEANUP_TIME = 60; // cleanup time in minutes
  420. /* Help: http://www.tectite.com/fmdoc/cleanup_chance.php */
  421. $CLEANUP_CHANCE = 20; // percentage probability that cleanup will be performed
  422. /* Help: http://www.tectite.com/fmdoc/pear_settings.php */
  423. $PEAR_SMTP_HOST = "";
  424. $PEAR_SMTP_PORT = 25;
  425. $PEAR_SMTP_USER = "";
  426. $PEAR_SMTP_PWD = "";
  427. /* Help: http://www.tectite.com/fmdoc/alert_on_user_error.php */
  428. define("ALERT_ON_USER_ERROR",true);
  429. /* Help: http://www.tectite.com/fmdoc/enable_attack_detection.php */
  430. define("ENABLE_ATTACK_DETECTION",true);
  431. /* Help: http://www.tectite.com/fmdoc/attack_detection_url.php */
  432. define("ATTACK_DETECTION_URL","");
  433. /* Help: http://www.tectite.com/fmdoc/alert_on_attack_detection.php */
  434. define("ALERT_ON_ATTACK_DETECTION",false);
  435. /* Help: http://www.tectite.com/fmdoc/attack_detection_mime.php */
  436. define("ATTACK_DETECTION_MIME",true);
  437. /* Help: http://www.tectite.com/fmdoc/attack_detection_junk.php */
  438. define("ATTACK_DETECTION_JUNK",false);
  439. define("ATTACK_DETECTION_JUNK_CONSONANTS","bcdfghjklmnpqrstvwxz");
  440. define("ATTACK_DETECTION_JUNK_VOWELS","aeiouy");
  441. define("ATTACK_DETECTION_JUNK_CONSEC_CONSONANTS",5);
  442. define("ATTACK_DETECTION_JUNK_CONSEC_VOWELS",4);
  443. define("ATTACK_DETECTION_JUNK_TRIGGER",2);
  444. $ATTACK_DETECTION_JUNK_LANG_STRIP = array(
  445. "aiia", /* Hawaiian */
  446. "aeoa", /* palaeoanthropic */
  447. "aeoe", /* palaeoethnic */
  448. "ooee", /* cooee */
  449. "oeia", /* pharmacopoeia */
  450. "ioau", /* radioautograph */
  451. "uaia", /* guaiac */
  452. "ueou", /* aqueous */
  453. "uiou", /* obsequious */
  454. "queue", /* queue, queueing */
  455. "earth", /* earthquake, earthslide */
  456. "cks", /* jockstrap, backscratcher */
  457. "ngth", /* strengths, length */
  458. "ndths", /* thousandths */
  459. "ght", /* nightclub, knightsbridge */
  460. "phth", /* ophthalmology */
  461. "sch", /* rothschild */
  462. "shch", /* borshch */
  463. "scr", /* corkscrew */
  464. "spr", /* wingspread, offspring */
  465. "str", /* armstrong, songstress */
  466. "sts", /* bursts, postscript */
  467. "tch", /* catchphrase, scratchproof */
  468. "thst", /* northstar, birthstone */
  469. "http", /* https, http */
  470. "html", /* HTML, XHTML */
  471. );
  472. $ATTACK_DETECTION_JUNK_IGNORE_FIELDS = array();
  473. /* Help: http://www.tectite.com/fmdoc/attack_detection_dups.php */
  474. $ATTACK_DETECTION_DUPS = array("realname","address1","address2","country","zip",
  475. "phone","postcode","state","email");
  476. /* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */
  477. define("ATTACK_DETECTION_SPECIALS",true);
  478. /* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */
  479. $ATTACK_DETECTION_SPECIALS_ONLY_EMAIL = array("derive_fields","required",
  480. "mail_options","good_url","bad_url","good_template",
  481. "bad_template");
  482. /* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */
  483. $ATTACK_DETECTION_SPECIALS_ANY_EMAIL = array("subject");
  484. /* Help: http://www.tectite.com/fmdoc/attack_detection_many_urls.php */
  485. define("ATTACK_DETECTION_MANY_URLS",0);
  486. /* Help: http://www.tectite.com/fmdoc/attack_detection_many_url_fields.php */
  487. define("ATTACK_DETECTION_MANY_URL_FIELDS",0);
  488. /* Help: http://www.tectite.com/fmdoc/attack_detection_url_patterns.php */
  489. $ATTACK_DETECTION_URL_PATTERNS = array(
  490. '(^|[^-a-z_.0-9]+)(?<!@)([-a-z0-9]+\.)+(com|org|net|biz|info|name|pro|tel|asia|cat)\b',
  491. '(^|[^-a-z_.0-9]+)(?<!@)([-a-z0-9]+\.)+(com{0,1}|org|net)\.[a-z][a-z]\b');
  492. /* Help: http://www.tectite.com/fmdoc/attack_detection_ignore_errors.php */
  493. define("ATTACK_DETECTION_IGNORE_ERRORS",false);
  494. /* Help: http://www.tectite.com/fmdoc/attack_detection_reverse_captcha.php */
  495. $ATTACK_DETECTION_REVERSE_CAPTCHA = array();
  496. /* Help: http://www.tectite.com/fmdoc/geoip_lic.php */
  497. $GEOIP_LIC = ""; // default - no GeoIP
  498. /* Help: http://www.tectite.com/fmdoc/zero_is_empty.php */
  499. define("ZERO_IS_EMPTY",false);
  500. /* Help: http://www.tectite.com/fmdoc/session_name.php */
  501. $SESSION_NAME = "";
  502. /* Help: http://www.tectite.com/fmdoc/session_access.php */
  503. $SESSION_ACCESS = array();
  504. /* Help: http://www.tectite.com/fmdoc/destroy_session.php */
  505. define("DESTROY_SESSION",true);
  506. /* Help: http://www.tectite.com/fmdoc/hook_dir.php */
  507. $HOOK_DIR = "";
  508. /* UPGRADE CONTROL
  509. **
  510. ** FILTERS:lt:8.04:merge:The FILTERS configuration has
  511. ** been modified to include some new standard filters.:
  512. **
  513. ** FILTER_ATTRIBS:lt:8.04:no_keep:The FILTER_ATTRIBS configuration has
  514. ** been modified to include new information about the standard filters.:
  515. **
  516. ** ATTACK_DETECTION_URL_PATTERNS:eq:8.02:no_keep:The ATTACK_DETECTION_URL_PATTERNS
  517. ** configuration has been modified to fix a bug.:
  518. **
  519. ** FILTER_ATTRIBS:lt:4.00:no_keep:The FILTER_ATTRIBS configuration has
  520. ** been modified to include new information about the standard filters.:
  521. **
  522. ** SET_REAL_DOCUMENT_ROOT:gt:4.07:copy_from=REAL_DOCUMENT_ROOT:The
  523. ** REAL_DOCUMENT_ROOT configuration has been renamed to SET_REAL_DOCUMENT_ROOT.:
  524. **
  525. ** EMAIL_NAME:lt:6.01:no_keep:The EMAIL_NAME configuration has
  526. ** been modified to match hyphens ('-') in email addresses.:
  527. **
  528. ** ZERO_IS_EMPTY:le:6.01:set_to=true:ZERO_IS_EMPTY has been
  529. ** set to a value that duplicates previous behaviour.:
  530. **
  531. ** TEXT_SUBS:lt:8.30:no_keep:The TEXT_SUBS configuration has
  532. ** been modified to be secure with new features released in this version.:
  533. **
  534. ** END OF CONTROL
  535. */
  536. /*****************************************************************************/
  537. /* END OF CONFIGURATION (do not alter this line in any way!!!) */
  538. /*****************************************************************************/
  539. //
  540. // for Ajax allow GET method for cross site JSONP
  541. //
  542. if (IsAjax())
  543. $ALLOW_GET_METHOD = true;
  544. /*
  545. * Load an optional include file after the configuration.
  546. * You can use this to set variables or make adjustments
  547. * based on the results of the configuration section.
  548. */
  549. @include("formmail-postconfig.inc.php");
  550. //
  551. // the following constants define all FormMail messages
  552. //
  553. define('MSG_SCRIPT_VERSION',0); // This script requires at least PHP version...
  554. define('MSG_END_VERS_CHK',1); // If you're happy...
  555. define('MSG_VERS_CHK',2); // A later version of FormMail is available...
  556. define('MSG_CHK_FILE_ERROR',3); // Unable to create check file...
  557. define('MSG_UNK_VALUE_SPEC',4); // derive_fields: unknown value specification...
  558. define('MSG_INV_VALUE_SPEC',5); // derive_fields: invalid value specification...
  559. define('MSG_DERIVED_INVALID',6); // Some derive_fields specifications...
  560. define('MSG_INT_FORM_ERROR',7); // Internal form error...
  561. define('MSG_OPTIONS_INVALID',8); // Some mail_options settings...
  562. define('MSG_PLSWAIT_REDIR',9); // Please wait while you are redirected...
  563. define('MSG_IFNOT_REDIR',10); // If you are not redirected...
  564. define('MSG_PEAR_OBJ',11); // Failed to create PEAR Mail object...
  565. define('MSG_PEAR_ERROR',12); // PEAR Mail error...
  566. define('MSG_NO_FOPT_ADDR',13); // You have specified "SendMailFOption"...
  567. define('MSG_MORE_INFO',14); // More information...
  568. define('MSG_INFO_STOPPED',15); // Extra alert information suppressed...
  569. define('MSG_FM_ALERT',16); // FormMail alert
  570. define('MSG_FM_ERROR',17); // FormMail script error
  571. define('MSG_FM_ERROR_LINE',18); // The following error occurred...
  572. define('MSG_USERDATA_STOPPED',19); // User data suppressed...
  573. define('MSG_FILTERED',20); // This alert has been filtered...
  574. define('MSG_TEMPLATES',21); // You must set either TEMPLATEDIR or TEMPLATEURL...
  575. define('MSG_OPEN_TEMPLATE',22); // Failed to open template...
  576. define('MSG_ERROR_PROC',23); // An error occurred while processing...
  577. define('MSG_ALERT_DONE',24); // Our staff have been alerted...
  578. define('MSG_PLS_CONTACT',25); // Please contact us directly...
  579. define('MSG_APOLOGY',26); // We apologize for any inconvenience...
  580. define('MSG_ABOUT_FORMMAIL',27); // Your form submission was processed by...
  581. define('MSG_PREG_FAILED',28); // preg_match_all failed in FindCRMFields...
  582. define('MSG_URL_INVALID',29); // CRM URL "$URL" is not valid...
  583. define('MSG_URL_OPEN',30); // Failed to open Customer Relationship...
  584. define('MSG_CRM_FAILED',31); // Failure report from CRM...
  585. define('MSG_CRM_FORM_ERROR',32); // Your form submission was not...
  586. define('MSG_OR',33); // "$ITEM1" or "$ITEM2"
  587. define('MSG_NOT_BOTH',34); // not both "$ITEM1" and "$ITEM2"
  588. define('MSG_XOR',35); // "$ITEM1" or "$ITEM2" (but not both)
  589. define('MSG_IS_SAME_AS',36); // "$ITEM1" is the same as "$ITEM2"
  590. define('MSG_IS_NOT_SAME_AS',37); // "$ITEM1" is not the same as "$ITEM2"
  591. define('MSG_REQD_OPER',38); // Operator "$OPER" is not valid for "required"
  592. define('MSG_PAT_FAILED',39); // Pattern operator "$OPER" failed: pattern...
  593. define('MSG_COND_OPER',40); // Operator "$OPER" is not valid...
  594. define('MSG_INV_COND',41); // Invalid "conditions" field...
  595. define('MSG_COND_CHARS',42); // The conditions field "$FLD" is not valid...
  596. define('MSG_COND_INVALID',43); // The conditions field "$FLD" is not valid...
  597. define('MSG_COND_TEST_LONG',44); // Field "$FLD" has too many components...
  598. define('MSG_COND_IF_SHORT',45); // Field "$FLD" has too few components for...
  599. define('MSG_COND_IF_LONG',46); // Field "$FLD" has too many components for...
  600. define('MSG_COND_UNK',47); // Field "$FLD" has an unknown command word...
  601. define('MSG_MISSING',48); // Missing "$ITEM"...
  602. define('MSG_NEED_ARRAY',49); // "$ITEM" must be an array...
  603. define('MSG_SUBM_FAILED',50); // Your form submission has failed...
  604. define('MSG_FILTER_WRONG',51); // Filter "$FILTER" is not properly...
  605. define('MSG_FILTER_CONNECT',52); // Could not connect to site "$SITE"...
  606. define('MSG_FILTER_PARAM',53); // Filter "$FILTER" has invalid parameter...
  607. define('MSG_FILTER_OPEN_FILE',54); // Filter "$FILTER" cannot open file...
  608. define('MSG_FILTER_FILE_ERROR',55); // Filter "$FILTER": read error on file...
  609. define('MSG_FILTER_READ_ERROR',56); // Filter '$filter' failed: read error...
  610. define('MSG_FILTER_NOT_OK',57); // Filter 'FILTER' failed...
  611. define('MSG_FILTER_UNK',58); // Unknown filter...
  612. define('MSG_FILTER_CHDIR',59); // Cannot chdir...
  613. define('MSG_FILTER_NOTFOUND',60); // Cannot execute...
  614. define('MSG_FILTER_ERROR',61); // Filter "$FILTER" failed...
  615. define('MSG_SPARE',62); // this value is now spare
  616. define('MSG_TEMPLATE_ERRORS',63); // Template "$NAME" caused the...
  617. define('MSG_TEMPLATE_FAILED',64); // Failed to process template "$NAME"...
  618. define('MSG_MIME_PREAMBLE',65); // (Your mail reader should not show this...
  619. define('MSG_MIME_HTML',66); // This message has been generated by FormMail...
  620. define('MSG_FILE_OPEN_ERROR',67); // Failed to open file "$NAME"...
  621. define('MSG_ATTACH_DATA',68); // Internal error: AttachFile requires...
  622. define('MSG_PHP_HTML_TEMPLATES',69); // HTMLTemplate option is only ...
  623. define('MSG_PHP_FILE_UPLOADS',70); // For security reasons, file upload...
  624. define('MSG_FILE_UPLOAD',71); // File upload attempt ignored...
  625. define('MSG_FILE_UPLOAD_ATTACK',72);// Possible file upload attack...
  626. define('MSG_PHP_PLAIN_TEMPLATES',73);// PlainTemplate option is only...
  627. define('MSG_ATTACH_NAME',74); // filter_options: Attach must contain a name...
  628. define('MSG_PHP_BCC',75); // Warning: BCC is probably not supported...
  629. define('MSG_CSVCOLUMNS',76); // The "csvcolumns" setting is not...
  630. define('MSG_CSVFILE',77); // The "csvfile" setting is not...
  631. define('MSG_TARG_EMAIL_PAT_START',78); // Warning: Your TARGET_EMAIL pattern...
  632. define('MSG_TARG_EMAIL_PAT_END',79); // Warning: Your TARGET_EMAIL pattern...
  633. define('MSG_CONFIG_WARN',80); // The following potential problems...
  634. define('MSG_PHP_AUTORESP',81); // Autorespond is only supported...
  635. define('MSG_ALERT',82); // This is a test alert message...
  636. define('MSG_NO_DEF_ALERT',83); // No DEF_ALERT value has been set....
  637. define('MSG_TEST_SENT',84); // Test message sent. Check your email.....
  638. define('MSG_TEST_FAILED',85); // FAILED to send alert message...
  639. define('MSG_NO_DATA_PAGE',86); // This URL is a Form submission program...
  640. define('MSG_REQD_ERROR',87); // The form required some values that you...
  641. define('MSG_COND_ERROR',88); // Some of the values you provided...
  642. define('MSG_CRM_FAILURE',89); // The form submission did not succeed...
  643. define('MSG_FOPTION_WARN',90); // Warning: You've used SendMailFOption in...
  644. define('MSG_NO_ACTIONS',91); // The form has an internal error...
  645. define('MSG_NO_RECIP',92); // The form has an internal error...
  646. define('MSG_INV_EMAIL',93); // Invalid email addresses...
  647. define('MSG_FAILED_SEND',94); // Failed to send email...
  648. define('MSG_ARESP_EMAIL',96); // No "email" field was found. Autorespond...
  649. define('MSG_ARESP_SUBJ',97); // Your form submission...
  650. define('MSG_LOG_NO_VERIMG',98); // No VerifyImgString in session...
  651. define('MSG_ARESP_NO_AUTH',99); // Failed to obtain authorization...
  652. define('MSG_LOG_NO_MATCH',100); // User did not match image...
  653. define('MSG_ARESP_NO_MATCH',101); // Your entry did not match...
  654. define('MSG_LOG_FAILED',102); // Failed
  655. define('MSG_ARESP_FAILED',103); // Autoresponder failed
  656. define('MSG_LOG_OK',104); // OK
  657. define('MSG_THANKS_PAGE',105); // Thanks! We've received your....
  658. define('MSG_LOAD_MODULE',106); // Cannot load module....
  659. define('MSG_LOAD_FMCOMPUTE',107); // Cannot load FMCompute....
  660. define('MSG_REGISTER_MODULE',108); // Cannot register module....
  661. define('MSG_COMP_PARSE',109); // These parse errors occurred....
  662. define('MSG_COMP_REG_DATA',110); // Failed to register data field....
  663. define('MSG_COMP_ALERT',111); // The following alert messages....
  664. define('MSG_COMP_DEBUG',112); // The following debug messages...
  665. define('MSG_COMP_EXEC',113); // The following errors occurred....
  666. define('MSG_REG_FMCOMPUTE',114); // Cannot register function...
  667. define('MSG_USER_ERRORS',115); // A number of errors occurred...
  668. define('MSG_CALL_PARAM_COUNT',116); // Invalid parameter count...
  669. define('MSG_CALL_UNK_FUNC',117); // Unknown function...
  670. define('MSG_SAVE_FILE',118); // Failed to save file....
  671. define('MSG_CHMOD',119); // Failed to chmod file....
  672. define('MSG_VERIFY_MISSING',120); // Image verification string missing...
  673. define('MSG_VERIFY_MATCH',121); // Your entry did not match...
  674. define('MSG_FILE_NAMES_INVALID',122);// Some file_names specifications...
  675. define('MSG_FILE_NAMES_NOT_FILE',123);// Your file_names specification...
  676. define('MSG_TEMPL_ALERT',124); // The following alert messages....
  677. define('MSG_TEMPL_DEBUG',125); // The following debug messages...
  678. define('MSG_TEMPL_PROC',126); // The following errors occurred....
  679. define('MSG_SAVE_FILE_EXISTS',127); // Cannot save file....
  680. define('MSG_EMPTY_ADDRESSES',128); // $COUNT empty addresses
  681. define('MSG_CALL_INVALID_PARAM',129); // Invalid parameter....
  682. define('MSG_INI_PARSE_WARN',130); // Warning: your INI
  683. define('MSG_INI_PARSE_ERROR',131); // The FormMail INI...
  684. define('MSG_RECAPTCHA_MATCH',132); // reCaptcha verification failed...
  685. define('MSG_AND',133); // "$ITEM1" and "$ITEM2"
  686. define('MSG_NEXT_PLUS_GOOD',134); // The form specifies both next_form and....
  687. define('MSG_MULTIFORM',135); // You must set either MULTIFORMDIR or MULTIFORMURL...
  688. define('MSG_MULTIFORM_FAILED',136); // Failed to process multi-page form template "$NAME"...
  689. define('MSG_NEED_THIS_FORM',137); // Multi-page forms require "this_form" field...
  690. define('MSG_NO_PHP_SELF',138); // PHP on the server is not providing "PHP_SELF"
  691. define('MSG_RETURN_URL_INVALID',139); // Return "$URL" is not valid...
  692. define('MSG_GO_BACK',140); // Cannot 'go back' if not a multi-page form...
  693. define('MSG_OPEN_URL',141); // Cannot open URL...
  694. define('MSG_CANNOT_RETURN',142); // Cannot return to page....
  695. define('MSG_ATTACK_DETECTED',143); // Server attack detected....
  696. define('MSG_ATTACK_PAGE',144); // Your form submission....
  697. define('MSG_ATTACK_MIME_INFO',145); // The field "$FLD" contained...
  698. define('MSG_ATTACK_DUP_INFO',146); // The fields "$FLD1" and...
  699. define('MSG_ATTACK_SPEC_INFO',147); // Special field "$FLD"...
  700. define('MSG_NEED_SCRATCH_PAD',148); // You need to set SCRATCH_PAD...
  701. define('MSG_MULTI_UPLOAD',149); // File upload processing failed during multi-page form processing.
  702. define('MSG_OPEN_SCRATCH_PAD',150); // Cannot open directory...
  703. define('MSG_NO_NEXT_NUM_FILE',151); // You cannot use the %nextnum% feature...
  704. define('MSG_NEXT_NUM_FILE',152); // Cannot process next number...
  705. define('MSG_ATTACK_MANYURL_INFO',153); // Field "$FLD"...
  706. define('MSG_ATTACK_MANYFIELDS_INFO',154); // $NUM fields have URLs....
  707. define('MSG_REV_CAP',155); // ATTACK_DETECTION_REVERSE_CAPTCHA setting....
  708. define('MSG_ATTACK_REV_CAP_INFO',156); // The field "$FLD" contained...
  709. define('MSG_ATTACK_JUNK_INFO',157); // The field "$FLD" contained...
  710. define('MSG_ARESP_EMPTY',158); // The autoresponse...
  711. define('MSG_LOG_RECAPTCHA',159); // reCaptcha process failed...
  712. define('MSG_URL_PARSE',160); // URL parse failed
  713. define('MSG_URL_SCHEME',161); // Unsupported URL scheme...
  714. define('MSG_SOCKET',162); // Socket error ...
  715. define('MSG_GETURL_OPEN',163); // Open URL failed: ...
  716. define('MSG_RESOLVE',164); // Cannot resolve...
  717. define('MSG_FORM_OK',170); // Form Submission Succeeded
  718. define('MSG_FORM_ERROR',171); // Form Submission Error
  719. define('MSG_GET_DISALLOWED',172); // GET method has...
  720. //
  721. // The following are PHP's file upload error messages
  722. //
  723. define('MSG_FILE_UPLOAD_ERR_UNK',180); // Unknown error code.
  724. define('MSG_FILE_UPLOAD_ERR1',181); // The uploaded file exceeds the upload_max_filesize directive in php.ini.
  725. define('MSG_FILE_UPLOAD_ERR2',182); // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.
  726. define('MSG_FILE_UPLOAD_ERR3',183); // The uploaded file was only partially uploaded.
  727. define('MSG_FILE_UPLOAD_ERR4',184); // No file was uploaded.
  728. define('MSG_FILE_UPLOAD_ERR6',186); // Missing a temporary folder.
  729. define('MSG_FILE_UPLOAD_ERR7',187); // Failed to write file to disk.
  730. define('MSG_FILE_UPLOAD_ERR8',188); // File upload stopped by extension.
  731. define('MSG_FILE_UPLOAD_SIZE',189); // Uploaded file "$NAME" is too big...
  732. // (not a PHP error code - internal maximum file size error)
  733. //
  734. // following are for derive_fields functions
  735. //
  736. define('MSG_DER_FUNC_ERROR',200); // derive_fields: invalid function....
  737. define('MSG_DER_FUNC_SIZE_FMT',201); // function 'size' requires....
  738. define('MSG_DER_FUNC_IF_FMT',202); // function 'if' requires....
  739. define('MSG_DER_FUNC_NEXTNUM_FMT',203); // function 'nextnum' requires....
  740. define('MSG_DER_FUNC_EXT_FMT',204); // function 'ext' requires....
  741. define('MSG_DER_FUNC1_FMT',205); // function 'FUNC' requires....
  742. define('MSG_USER_ATTACK_JUNK',220); // The following input ...
  743. define('MSG_USER_ATTACK_REV_CAP',221); // Your input ...
  744. define('MSG_USER_ATTACK_DUP',222); // You have ...
  745. define('MSG_USER_ATTACK_MANY_URLS',223);// Your input ...
  746. define('MSG_USER_ATTACK_MANY_URL_FIELDS',224);// Your input ...
  747. // <A NAME="MessageNumbers"> Jump to: <A HREF="#BuiltinMessages">
  748. //
  749. // Return true if using the built-in language
  750. //
  751. function IsBuiltInLanguage()
  752. {
  753. global $sLangID;
  754. return (strpos($sLangID,"builtin") !== false);
  755. }
  756. $sSavePath = "";
  757. $bPathSaved = false;
  758. //
  759. // Set include path to include the given directory.
  760. //
  761. function AddIncludePath($s_dir = ".")
  762. {
  763. global $sSavePath,$bPathSaved;
  764. $s_path = ini_get('include_path');
  765. $i_path_len = strlen($s_path);
  766. $s_sep = IsServerWindows() ? ";" : ":"; // get path separator
  767. //
  768. // look for it in the include_path
  769. //
  770. $b_found = false;
  771. $i_pos = 0;
  772. $i_len = strlen($s_dir);
  773. while (!$b_found && ($i_pos = strpos($s_path,$s_dir,$i_pos)) !== false)
  774. {
  775. if ($i_pos == 0)
  776. {
  777. if ($i_len == $i_path_len)
  778. $b_found = true; // the path only has $s_dir
  779. elseif ($s_path[$i_len] == $s_sep)
  780. $b_found = true;
  781. }
  782. elseif ($s_path[$i_pos-1] == $s_sep &&
  783. ($i_pos + $i_len == $i_path_len ||
  784. $s_path[$i_pos + $i_len] == $s_sep))
  785. $b_found = true;
  786. if (!$b_found)
  787. $i_pos++;
  788. }
  789. if (!$b_found)
  790. {
  791. //
  792. // allow multiple calls, but only store the original path once
  793. //
  794. if (!$bPathSaved)
  795. $sSavePath = $s_path;
  796. if (empty($s_path))
  797. $s_path = $s_dir;
  798. else
  799. //
  800. // prepend the directory
  801. //
  802. $s_path = $s_dir.$s_sep.$s_path;
  803. ini_set('include_path',$s_path);
  804. $bPathSaved = true;
  805. }
  806. }
  807. //
  808. // Reset the include path after a call to AddIncludePath.
  809. //
  810. function ResetIncludePath()
  811. {
  812. global $sSavePath,$bPathSaved;
  813. if ($bPathSaved)
  814. {
  815. ini_set('include_path',$sSavePath);
  816. $bPathSaved = false;
  817. }
  818. }
  819. //
  820. // Load a language file
  821. //
  822. function LoadLanguageFile()
  823. {
  824. global $aMessages,$sLangID,$sHTMLCharSet;
  825. AddIncludePath();
  826. if (!@include("language.inc.php"))
  827. @include("language.inc");
  828. ResetIncludePath();
  829. if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  830. header("Content-Type: text/html; charset=$sHTMLCharSet");
  831. }
  832. //
  833. // Load the messages array from the default language, and then
  834. // override with an optional language file.
  835. // Note: all messages get the MNUM parameter sent which they can use.
  836. // If they don't use it, the message number is appended.
  837. //
  838. function LoadBuiltinLanguage()
  839. {
  840. global $aMessages,$sLangID;
  841. $sLangID = "English (builtin)";
  842. // MSG_SCRIPT_VERSION is shown if the PHP version is too old to run
  843. // FormMail
  844. // Parameters:
  845. // $PHPREQ is the minimum required PHP version
  846. // $PHPVERS is the version the server currently has installed.
  847. $aMessages[MSG_SCRIPT_VERSION] = 'This script requires at least PHP version '.
  848. '$PHPREQ. You have PHP version $PHPVERS.';
  849. // MSG_END_VERS_CHK is sent at the end of an Alert message when
  850. // FormMail detects that there's a newer version available
  851. // Parameters: none
  852. $aMessages[MSG_END_VERS_CHK] = '***************************************************\n'.
  853. 'If you are happy with your current version and want\n'.
  854. 'to stop these reminders, edit formmail.php and\n'.
  855. 'set CHECK_FOR_NEW_VERSION to false.\n'.
  856. '***************************************************\n';
  857. // MSG_VERS_CHK is sent in an Alert message when
  858. // FormMail detects that there's a newer version available
  859. // Parameters:
  860. // $TECTITE the website to go to
  861. // $FM_VERS the current FormMail version
  862. // $NEWVERS the new FormMail version that's available
  863. $aMessages[MSG_VERS_CHK] = 'A later version of FormMail is available from $TECTITE.\n'.
  864. 'You are currently using version $FM_VERS.\n'.
  865. 'The new version available is $NEWVERS.\n';
  866. // MSG_CHK_FILE_ERROR is sent in an Alert message when
  867. // FormMail cannot create a file to record the time of version check.
  868. // Parameters:
  869. // $FILE the file name that could not be created
  870. // $ERROR the actual error message
  871. $aMessages[MSG_CHK_FILE_ERROR] = 'Unable to create check file "$FILE": $ERROR';
  872. // MSG_UNK_VALUE_SPEC is sent in an Alert message when
  873. // a form uses an unknown value specification in derive_fields.
  874. // Parameters:
  875. // $SPEC the unknown value specification
  876. // $MSG additional message
  877. $aMessages[MSG_UNK_VALUE_SPEC] = 'derive_fields: unknown value specification '.
  878. '"$SPEC"$MSG';
  879. // MSG_INV_VALUE_SPEC is sent in an Alert message when
  880. // a form uses a value specification in derive_fields that's
  881. // formatted incorrectly (missing terminating '%')
  882. // Parameters:
  883. // $SPEC the invalid value specification
  884. $aMessages[MSG_INV_VALUE_SPEC] = 'derive_fields: invalid value specification '.
  885. '"$SPEC" (possibly missing a "%")';
  886. // MSG_DERIVED_INVALID is sent in an Alert message when
  887. // a form's derive_fields setting has errors
  888. // Parameters: none
  889. // A list of errors is appended on separate lines
  890. $aMessages[MSG_DERIVED_INVALID] = 'Some derive_fields specifications are invalid $MNUM:\n';
  891. // MSG_INT_FORM_ERROR is sent in an Alert message and displayed
  892. // to the form user
  893. // Parameters: none
  894. $aMessages[MSG_INT_FORM_ERROR] = 'Internal form error';
  895. // MSG_OPTIONS_INVALID is sent in an Alert message when
  896. // a form's options settings are invalid. This applies to
  897. // mail_options, filter_options, crm_options, and autorespond
  898. // Parameters:
  899. // $OPT the name of the options field
  900. // A list of errors is appended on separate lines
  901. $aMessages[MSG_OPTIONS_INVALID] = 'Some $OPT settings are undefined $MNUM:\n';
  902. // MSG_PLSWAIT_REDIR is shown to the user for a redirect
  903. // with JavaScript
  904. // Parameters: none
  905. $aMessages[MSG_PLSWAIT_REDIR] = 'Please wait while you are redirected...';
  906. // MSG_IFNOT_REDIR is shown to the user for a redirect
  907. // with JavaScript
  908. // Parameters:
  909. // $URL the URL to redirect to
  910. $aMessages[MSG_IFNOT_REDIR] = 'If you are not automatically redirected, '.
  911. 'please <a href="$URL">click here</a>.';
  912. // MSG_PEAR_OBJ is shown to the user if the PEAR Mail object
  913. // cannot be created
  914. // Parameters: none
  915. $aMessages[MSG_PEAR_OBJ] = 'Failed to create PEAR Mail object';
  916. // MSG_PEAR_ERROR is sent in an Alert message if the PEAR Mail processing
  917. // reports an error
  918. // Parameters:
  919. // $MSG the error message from PEAR
  920. $aMessages[MSG_PEAR_ERROR] = 'PEAR Mail error: $MSG';
  921. // MSG_NO_FOPT_ADDR is sent in an Alert message SendMailFOption is
  922. // specified in the form and no email address has been provided
  923. // Parameters: none
  924. $aMessages[MSG_NO_FOPT_ADDR] = 'You have specified "SendMailFOption" in your '.
  925. 'form, but there is no email address to use';
  926. // MSG_MORE_INFO is sent in an Alert message on a line by itself, just
  927. // before extra information about the FormMail processing that may have
  928. // led to the alert message
  929. // Parameters: none
  930. $aMessages[MSG_MORE_INFO] = 'More information:';
  931. // MSG_INFO_STOPPED is sent in an Alert message to say that extra
  932. // alert information has been suppressed because of potential security
  933. // problems with showing it.
  934. // Parameters: none
  935. $aMessages[MSG_INFO_STOPPED] = '(Extra alert information suppressed for '.
  936. 'security purposes. $MNUM)';
  937. // MSG_FM_ALERT is sent as the subject line of an Alert message
  938. // Parameters: none
  939. $aMessages[MSG_FM_ALERT] = 'FormMail alert';
  940. // MSG_FM_ERROR is sent as the subject line of an Alert message
  941. // Parameters: none
  942. $aMessages[MSG_FM_ERROR] = 'FormMail script error';
  943. // MSG_FM_ERROR_LINE is sent in an Alert message on a
  944. // separate line to introduce the actual error message
  945. // Parameters: none
  946. $aMessages[MSG_FM_ERROR_LINE] = 'The following error occurred in FormMail $MNUM:';
  947. // MSG_USERDATA_STOPPED is sent in an Alert message to say that the
  948. // user's data has been suppressed because of potential security
  949. // problems with showing it.
  950. // Parameters: none
  951. $aMessages[MSG_USERDATA_STOPPED] = '(User data suppressed for security '.
  952. 'purposes. $MNUM)';
  953. // MSG_FILTERED is sent in an Alert message to show what filter
  954. // has been used on the message
  955. // Parameters:
  956. // $FILTER the name of the filter
  957. $aMessages[MSG_FILTERED] = 'This alert has been filtered through "$FILTER" '.
  958. 'for security purposes.';
  959. // MSG_TEMPLATES is sent in an Alert message when a form tries
  960. // to use a template, but templates have not been configured in
  961. // formmail.php
  962. // Parameters: none
  963. $aMessages[MSG_TEMPLATES] = 'You must set either TEMPLATEDIR or TEMPLATEURL '.
  964. 'in formmail.php before you can specify '.
  965. 'templates in your forms.';
  966. // MSG_OPEN_TEMPLATE is sent in an Alert message when FormMail cannot
  967. // open a template file
  968. // Parameters:
  969. // $NAME the name of the template file
  970. // $ERROR information about the error
  971. $aMessages[MSG_OPEN_TEMPLATE] = 'Failed to open template "$NAME" $MNUM: $ERROR';
  972. // MSG_ERROR_PROC is shown to the user as part of an error
  973. // page. This message introduces the error.
  974. // Parameters: none
  975. $aMessages[MSG_ERROR_PROC] = 'An error occurred while processing the '.
  976. 'form $MNUM.\n\n';
  977. // MSG_ALERT_DONE is shown to the user as part of an error
  978. // page if an Alert message has been sent to the website owner.
  979. // Parameters:
  980. // SERVER the name of the server (website)
  981. $aMessages[MSG_ALERT_DONE] = 'The staff at $SERVER have been alerted to the error $MNUM.\n';
  982. // MSG_PLS_CONTACT is shown to the user as part of an error
  983. // page if an Alert message could *not* be sent to the website owner.
  984. // Parameters:
  985. // SERVER the name of the server (website)
  986. $aMessages[MSG_PLS_CONTACT] = 'Please contact us ($SERVER) directly since this form '.
  987. 'is not working $MNUM.\n';
  988. // MSG_APOLOGY is shown to the user as part of an error
  989. // page as an apology for a problem with the form.
  990. // Parameters:
  991. // SERVER the name of the server (website)
  992. $aMessages[MSG_APOLOGY] = '$SERVER apologizes for any inconvenience this error '.
  993. 'may have caused.';
  994. // MSG_ABOUT_FORMMAIL is shown to the user at the foot of pages
  995. // generated by FormMail (e.g. the default "Thanks" page and default
  996. // error page).
  997. // Parameters:
  998. // $FM_VERS the FormMail version number
  999. // $TECTITE www.tectite.com
  1000. $aMessages[MSG_ABOUT_FORMMAIL] = 'Your form submission was processed by '.
  1001. '<a href="http://$TECTITE/">FormMail</a> '.
  1002. '($FM_VERS), a PHP script available from '.
  1003. '<a href="http://$TECTITE/">$TECTITE</a>.';
  1004. // MSG_PREG_FAILED is sent in an Alert message if the TectiteCRM
  1005. // system failed to return the expected result.
  1006. // Parameters: none
  1007. $aMessages[MSG_PREG_FAILED] = 'preg_match_all failed in FindCRMFields';
  1008. // MSG_URL_INVALID is sent in an Alert message if the specified
  1009. // URL for TectiteCRM is not valid according to the TARGET_URLS
  1010. // configuration setting
  1011. // Parameters:
  1012. // $URL the invalid URL
  1013. $aMessages[MSG_URL_INVALID] = 'The URL "$URL" to access the Customer '.
  1014. 'Relationship Management System is not valid '.
  1015. '(see TARGET_URLS in formmail.php)';
  1016. // MSG_URL_OPEN is sent in an Alert message if the specified
  1017. // URL for TectiteCRM cannot be opened
  1018. // Parameters:
  1019. // $URL the invalid URL
  1020. // $ERROR information about the error
  1021. $aMessages[MSG_URL_OPEN] = 'Failed to open Customer Relationship '.
  1022. 'Management System URL "$URL" $MNUM: $ERROR';
  1023. // MSG_CRM_FAILED is sent in an Alert message if the TectiteCRM
  1024. // system doesn't return an OK message
  1025. // Parameters:
  1026. // $URL the invalid URL
  1027. // $MSG more information
  1028. $aMessages[MSG_CRM_FAILED] = 'Failure report from Customer Relationship '.
  1029. 'Management System (url="$URL") $MNUM: $MSG';
  1030. // MSG_CRM_FORM_ERROR is shown to the user if the information
  1031. // passed to TectiteCRM was not accepted
  1032. // Parameters: none
  1033. $aMessages[MSG_CRM_FORM_ERROR] = 'Your form submission was not accepted';
  1034. // MSG_AND is shown to the user; it shows two items separated
  1035. // by "and"
  1036. // Parameters:
  1037. // $ITEM1 the first item
  1038. // $ITEM2 the second item
  1039. $aMessages[MSG_AND] = '"$ITEM1" and "$ITEM2"';
  1040. // MSG_OR is shown to the user; it shows two items separated
  1041. // by "or"
  1042. // Parameters:
  1043. // $ITEM1 the first item
  1044. // $ITEM2 the second item
  1045. $aMessages[MSG_OR] = '"$ITEM1" or "$ITEM2"';
  1046. // MSG_NOT_BOTH is shown to the user; it shows two items that must
  1047. // be specified together
  1048. // Parameters:
  1049. // $ITEM1 the first item
  1050. // $ITEM2 the second item
  1051. $aMessages[MSG_NOT_BOTH] = 'not both "$ITEM1" and "$ITEM2"';
  1052. // MSG_XOR is shown to the user; it shows two items that must
  1053. // not be specified together
  1054. // Parameters:
  1055. // $ITEM1 the first item
  1056. // $ITEM2 the second item
  1057. $aMessages[MSG_XOR] = '"$ITEM1" or "$ITEM2" (but not both)';
  1058. // MSG_IS_SAME_AS is shown to the user; it shows two items that must
  1059. // not be the same value
  1060. // Parameters:
  1061. // $ITEM1 the first item
  1062. // $ITEM2 the second item
  1063. $aMessages[MSG_IS_SAME_AS] = '"$ITEM1" is the same as "$ITEM2"';
  1064. // MSG_IS_NOT_SAME_AS is shown to the user; it shows two items that must
  1065. // be the same value
  1066. // Parameters:
  1067. // $ITEM1 the first item
  1068. // $ITEM2 the second item
  1069. $aMessages[MSG_IS_NOT_SAME_AS] = '"$ITEM1" is not the same as "$ITEM2"';
  1070. // MSG_REQD_OPER is sent in an Alert message when an unknown
  1071. // operator has been used in a "required" specification
  1072. // Parameters:
  1073. // $OPER the unknown operator
  1074. $aMessages[MSG_REQD_OPER] = 'Operator "$OPER" is not valid for "required"';
  1075. // MSG_PAT_FAILED is sent in an Alert message when a "conditions" pattern
  1076. // match has not matched anything (this isn't necessarily an error)
  1077. // Parameters:
  1078. // $OPER the "conditions" operator
  1079. // $PAT the "conditions" pattern
  1080. // $VALUE the value that was searched
  1081. $aMessages[MSG_PAT_FAILED] = 'Pattern operator "$OPER" failed: pattern '.
  1082. '"$PAT", value searched was "$VALUE".';
  1083. // MSG_COND_OPER is sent in an Alert message when a "conditions"
  1084. // operator is not value
  1085. // Parameters:
  1086. // $OPER the "conditions" operator
  1087. $aMessages[MSG_COND_OPER] = 'Operator "$OPER" is not valid for "conditions"';
  1088. // MSG_INV_COND is sent in an Alert message when a "conditions"
  1089. // field is not valid
  1090. // Parameters:
  1091. // FLD the field name
  1092. $aMessages[MSG_INV_COND] = 'Invalid "conditions" field "$FLD" - not a string or array.';
  1093. // MSG_COND_CHARS is sent in an Alert message when a "conditions"
  1094. // field is missing the mandatory first 2 characters (the separators)
  1095. // Parameters:
  1096. // FLD the field name
  1097. // COND the conditions field value
  1098. $aMessages[MSG_COND_CHARS] = 'The conditions field "$FLD" is not valid. '.
  1099. 'You must provide the two separator '.
  1100. 'characters at the beginning. You had "$COND".';
  1101. // MSG_COND_INVALID is sent in an Alert message when a "conditions"
  1102. // field has the wrong format
  1103. // Parameters:
  1104. // FLD the field name
  1105. // COND the conditions field value
  1106. // SEP the internal separator character for the field.
  1107. $aMessages[MSG_COND_INVALID] = 'The conditions field "$FLD" is not valid. '.
  1108. 'There must be at least 5 components '.
  1109. 'separated by "$SEP". Your value was "$COND".';
  1110. // MSG_COND_TEST_LONG is sent in an Alert message when a "conditions"
  1111. // TEST value has too many components
  1112. // Parameters:
  1113. // FLD the field name
  1114. // COND the conditions field value
  1115. // SEP the list separator character for the field.
  1116. $aMessages[MSG_COND_TEST_LONG] = 'Field "$FLD" has too many components for '.
  1117. 'a "TEST" command: "$COND".\nAre you missing '.
  1118. 'a "$SEP"?';
  1119. // MSG_COND_IF_SHORT is sent in an Alert message when a "conditions"
  1120. // IF value has too few components
  1121. // Parameters:
  1122. // FLD the field name
  1123. // COND the conditions field value
  1124. // SEP the internal separator character for the field.
  1125. $aMessages[MSG_COND_IF_SHORT] = 'Field "$FLD" has too few components for '.
  1126. 'an "IF" command: "$COND".\nThere must be '.
  1127. 'at least 6 components separated by "$SEP"';
  1128. // MSG_COND_IF_LONG is sent in an Alert message when a "conditions"
  1129. // IF value has too many components
  1130. // Parameters:
  1131. // FLD the field name
  1132. // COND the conditions field value
  1133. // SEP the list separator character for the field.
  1134. $aMessages[MSG_COND_IF_LONG] = 'Field "$FLD" has too many components for '.
  1135. 'an "IF" command: "$COND".\nAre you missing '.
  1136. 'a "$SEP"?';
  1137. // MSG_COND_UNK is sent in an Alert message when a "conditions"
  1138. // value has an unknown command
  1139. // Parameters:
  1140. // FLD the field name
  1141. // COND the conditions field value
  1142. // CMD the unknown command
  1143. $aMessages[MSG_COND_UNK] = 'Field "$FLD" has an unknown command word '.
  1144. '"$CMD": "$COND".';
  1145. // MSG_MISSING is sent in an Alert message when
  1146. // a socket filter is incorrectly defined
  1147. // Parameters:
  1148. // ITEM the missing item
  1149. $aMessages[MSG_MISSING] = 'Missing "$ITEM"';
  1150. // MSG_NEED_ARRAY is sent in an Alert message when
  1151. // a socket filter is incorrectly defined
  1152. // Parameters:
  1153. // ITEM the item that should be an array
  1154. $aMessages[MSG_NEED_ARRAY] = '"$ITEM" must be an array';
  1155. // MSG_SUBM_FAILED is shown to the user when an internal error
  1156. // as occurred and that error is not to be shown
  1157. // Parameters: none
  1158. $aMessages[MSG_SUBM_FAILED] = 'Your form submission has failed due to '.
  1159. 'an error on our server.';
  1160. // MSG_FILTER_WRONG is sent in an Alert message when
  1161. // a socket filter is incorrectly defined
  1162. // Parameters:
  1163. // FILTER the filter name
  1164. // ERRORS a string containing a list of errors
  1165. $aMessages[MSG_FILTER_WRONG] = 'Filter "$FILTER" is not properly defined: '.
  1166. '$ERRORS';
  1167. // MSG_FILTER_CONNECT is sent in an Alert message when FormMail
  1168. // cannot connect to a socket filter
  1169. // Parameters:
  1170. // FILTER the filter name
  1171. // SITE the site
  1172. // ERRNUM socket error number
  1173. // ERRSTR socket error message
  1174. $aMessages[MSG_FILTER_CONNECT] = 'Could not connect to site "$SITE" '.
  1175. 'for filter "$FILTER" ($ERRNUM): $ERRSTR';
  1176. // MSG_FILTER_PARAM is sent in an Alert message when a socket
  1177. // filter has an invalid parameter specification
  1178. // Parameters:
  1179. // FILTER the filter name
  1180. // NUM parameter number
  1181. // NAME parameter name
  1182. $aMessages[MSG_FILTER_PARAM] = 'Filter "$FILTER" has invalid parameter '.
  1183. '#$NUM: no "$NAME"';
  1184. // MSG_FILTER_OPEN_FILE is sent in an Alert message when a socket
  1185. // filter cannot open the required file
  1186. // Parameters:
  1187. // FILTER the filter name
  1188. // FILE the file that could not be opened
  1189. // ERROR the error message
  1190. $aMessages[MSG_FILTER_OPEN_FILE] = 'Filter "$FILTER" cannot open file '.
  1191. '"$FILE": $ERROR';
  1192. // MSG_FILTER_FILE_ERROR is sent in an Alert message when a socket
  1193. // filter gets an error message during reading a file
  1194. // Parameters:
  1195. // FILTER the filter name
  1196. // FILE the file that could not be opened
  1197. // ERROR the error message
  1198. // NLINES the number of lines that were read successfully
  1199. $aMessages[MSG_FILTER_FILE_ERROR] = 'Filter "$FILTER": read error on file '.
  1200. '"$FILE" after $NLINES lines: $ERROR';
  1201. // MSG_FILTER_READ_ERROR is sent in an Alert message when a socket
  1202. // filter gets an error during reading from the socket
  1203. // Parameters:
  1204. // FILTER the filter name
  1205. // ERROR the error message
  1206. $aMessages[MSG_FILTER_READ_ERROR] = 'Filter "$FILTER" failed: read error: '.
  1207. '$ERROR';
  1208. // MSG_FILTER_NOT_OK is sent in an Alert message when a socket
  1209. // filter fails to return the agreed __OK__ indicator
  1210. // Parameters:
  1211. // FILTER the filter name
  1212. // DATA the data returned from the filter
  1213. $aMessages[MSG_FILTER_NOT_OK] = 'Filter "$FILTER" failed (missing '.
  1214. '__OK__ line): $DATA';
  1215. // MSG_FILTER_UNK is sent in an Alert message
  1216. // when an unknown filter is specified by a form
  1217. // Parameters:
  1218. // FILTER the filter name
  1219. $aMessages[MSG_FILTER_UNK] = 'Unknown filter "$FILTER"';
  1220. // MSG_FILTER_CHDIR is sent in an Alert message
  1221. // when FormMail cannot change to the filter's directory
  1222. // Parameters:
  1223. // FILTER the filter name
  1224. // DIR the directory name
  1225. // ERROR an error message from the system
  1226. $aMessages[MSG_FILTER_CHDIR] = 'Cannot chdir to "$DIR" to run filter '.
  1227. '"$FILTER": $ERROR';
  1228. // MSG_FILTER_NOTFOUND is sent in an Alert message
  1229. // when FormMail cannot execute the filter
  1230. // Parameters:
  1231. // FILTER the filter name
  1232. // CMD the command line being executed
  1233. // ERROR an error message from the system
  1234. $aMessages[MSG_FILTER_NOTFOUND] = 'Cannot execute filter "$FILTER" with '.
  1235. 'command "$CMD": $ERROR';
  1236. // MSG_FILTER_ERROR is sent in an Alert message
  1237. // when a filter returns a non-zero status
  1238. // Parameters:
  1239. // FILTER the filter name
  1240. // ERROR an error message from the system
  1241. // STATUS the status return from the command
  1242. $aMessages[MSG_FILTER_ERROR] = 'Filter "$FILTER" failed (status $STATUS): '.
  1243. '$ERROR';
  1244. // MSG_SPARE is a spare message
  1245. $aMessages[MSG_SPARE] = '';
  1246. // MSG_TEMPLATE_ERRORS is sent as part of an Alert message
  1247. // when a template has generated some errors. The message
  1248. // should end with a new line and the actual errors are
  1249. // output after it.
  1250. // Parameters:
  1251. // NAME the template name
  1252. $aMessages[MSG_TEMPLATE_ERRORS] = 'Template "$NAME" caused the '.
  1253. 'following errors $MNUM:\n';
  1254. // MSG_TEMPLATE_FAILED is sent in an Alert message
  1255. // when processing a template has failed.
  1256. // Parameters:
  1257. // NAME the template name
  1258. $aMessages[MSG_TEMPLATE_FAILED] = 'Failed to process template "$NAME"';
  1259. // MSG_MIME_PREAMBLE is sent in the preamble of MIME emails
  1260. // Parameters: none
  1261. $aMessages[MSG_MIME_PREAMBLE] = '(Your mail reader should not show this '.
  1262. 'text.\nIf it does you may need to '.
  1263. 'upgrade to more modern software.)';
  1264. // MSG_MIME_HTML is sent in the preamble of HTML emails
  1265. // Parameters:
  1266. // NAME the template name
  1267. $aMessages[MSG_MIME_HTML] = 'This message has been generated by FormMail '.
  1268. 'using an HTML template\ncalled "$NAME". The '.
  1269. 'raw text of the form results\nhas been '.
  1270. 'included below, but your mail reader should '.
  1271. 'display the HTML\nversion only (unless it\'s '.
  1272. 'not capable of doing so).';
  1273. // MSG_FILE_OPEN_ERROR is sent in an Alert message when FormMail
  1274. // cannot open a file
  1275. // Parameters:
  1276. // NAME the file name
  1277. // TYPE the type of file
  1278. // ERROR the system error message
  1279. $aMessages[MSG_FILE_OPEN_ERROR] = 'Failed to open $TYPE file "$NAME": $ERROR';
  1280. // MSG_ATTACH_DATA is sent in an Alert message when the file
  1281. // attachment through 'data' has gone wrong.
  1282. // Parameters: none
  1283. $aMessages[MSG_ATTACH_DATA] = 'Internal error: AttachFile requires '.
  1284. '"tmp_name" or "data"';
  1285. // MSG_PHP_HTML_TEMPLATES is sent in an Alert message when an
  1286. // HTML template is used but the PHP version is too old.
  1287. // Parameters:
  1288. // $PHPVERS the current PHP version
  1289. $aMessages[MSG_PHP_HTML_TEMPLATES] = 'HTMLTemplate option is only supported '.
  1290. 'with PHP version 4.0.5 or above. Your '.
  1291. 'server is running version $PHPVERS.';
  1292. // MSG_PHP_FILE_UPLOADS is sent in an Alert message when
  1293. // file upload is used but the PHP version is too old.
  1294. // Parameters:
  1295. // $PHPVERS the current PHP version
  1296. $aMessages[MSG_PHP_FILE_UPLOADS] = 'For security reasons, file upload is only '.
  1297. 'allowed with PHP version 4.0.3 or above. '.
  1298. 'Your server is running version $PHPVERS.';
  1299. // MSG_FILE_UPLOAD is sent in an Alert message when
  1300. // file upload is attempted but FormMail is not configured to allow
  1301. // it
  1302. // Parameters: none
  1303. $aMessages[MSG_FILE_UPLOAD] = 'File upload attempt ignored';
  1304. // MSG_FILE_UPLOAD_ATTACK is sent in an Alert message when
  1305. // possible file upload attack is detected
  1306. // Parameters:
  1307. // NAME file name
  1308. // TEMP temporary file name
  1309. // FLD name of the file upload field
  1310. $aMessages[MSG_FILE_UPLOAD_ATTACK] = 'Possible file upload attack '.
  1311. 'detected: field="$FLD", name="$NAME" '.
  1312. 'temp name="$TEMP"';
  1313. // MSG_PHP_PLAIN_TEMPLATES is sent in an Alert message when a
  1314. // Plain template is used but the PHP version is too old.
  1315. // Parameters:
  1316. // $PHPVERS the current PHP version
  1317. $aMessages[MSG_PHP_PLAIN_TEMPLATES] = 'PlainTemplate option is only supported '.
  1318. 'with PHP version 4.0.5 or above. Your '.
  1319. 'server is running version $PHPVERS.';
  1320. // MSG_ATTACH_NAME is sent in an Alert message when a
  1321. // the form uses the Attach feature without specifying a file name
  1322. // Parameters: none
  1323. $aMessages[MSG_ATTACH_NAME] = 'filter_options: Attach must contain a name '.
  1324. '(e.g. Attach=data.txt)';
  1325. // MSG_PHP_BCC is sent in an Alert message when a
  1326. // the form uses the BCC feature and the PHP version may not support it
  1327. // Parameters:
  1328. // $PHPVERS the current PHP version
  1329. $aMessages[MSG_PHP_BCC] = 'Warning: BCC is probably not supported on your '.
  1330. 'PHP version ($PHPVERS)';
  1331. // MSG_CSVCOLUMNS is sent in an Alert message when a csvcolumns field
  1332. // is not correct
  1333. // Parameters:
  1334. // $VALUE the csvcolumns field value
  1335. $aMessages[MSG_CSVCOLUMNS] = 'The "csvcolumns" setting is not '.
  1336. 'valid: "$VALUE"';
  1337. // MSG_CSVFILE is sent in an Alert message when a csvfile field
  1338. // is not correct
  1339. // Parameters:
  1340. // $VALUE the csvfile field value
  1341. $aMessages[MSG_CSVFILE] = 'The "csvfile" setting is not valid: "$VALUE"';
  1342. // MSG_TARG_EMAIL_PAT_START is sent in an Alert message when a
  1343. // $TARGET_EMAIL pattern is insecure because of a missing '^'
  1344. // at the beginning
  1345. // Parameters:
  1346. // $PAT the pattern
  1347. $aMessages[MSG_TARG_EMAIL_PAT_START] = 'Warning: Your TARGET_EMAIL pattern '.
  1348. '"$PAT" is missing a ^ at the '.
  1349. 'beginning.';
  1350. // MSG_TARG_EMAIL_PAT_END is sent in an Alert message when a
  1351. // $TARGET_EMAIL pattern is insecure because of a missing '$'
  1352. // at the end
  1353. // Parameters:
  1354. // $PAT the pattern
  1355. $aMessages[MSG_TARG_EMAIL_PAT_END] = 'Warning: Your TARGET_EMAIL pattern '.
  1356. '"$PAT" is missing a $ at the end.';
  1357. // MSG_CONFIG_WARN is sent in an Alert message when the FormMail
  1358. // configuration may have some problems. The messages are
  1359. // passed on separate lines, so the line terminations below
  1360. // are important.
  1361. // Parameters:
  1362. // $MESGS lines of messages
  1363. $aMessages[MSG_CONFIG_WARN] = 'The following potential problems were found '.
  1364. 'in your configuration:\n$MESGS\n\n'.
  1365. 'These are not necessarily errors, but you '.
  1366. 'should review the documentation\n'.
  1367. 'inside formmail.php. If you are sure your '.
  1368. 'configuration is correct\n'.
  1369. 'you can disable the above messages by '.
  1370. 'changing the CONFIG_CHECK settings.';
  1371. // MSG_PHP_AUTORESP is sent in an Alert message when the PHP version
  1372. // does not support autoresponding
  1373. // Parameters:
  1374. // $PHPVERS current PHP version
  1375. $aMessages[MSG_PHP_AUTORESP] = 'Autorespond is only supported with PHP '.
  1376. 'version 4.0.5 or above. Your server is '.
  1377. 'running version $PHPVERS.';
  1378. // MSG_ALERT is the test alert message (formmail.php?testalert=1)
  1379. // Parameters:
  1380. // $LANG the language ID
  1381. // $PHPVERS PHP version
  1382. // $FM_VERS FormMail version
  1383. // $SERVER server type
  1384. // $DOCUMENT_ROOT PHP's DOCUMENT_ROOT value
  1385. // $SCRIPT_FILENAME PHP's SCRIPT_FILENAME value
  1386. // $PATH_TRANSLATED PHP's PATH_TRANSLATED value
  1387. // $REAL_DOCUMENT_ROOT the REAL_DOCUMENT_ROOT value
  1388. $aMessages[MSG_ALERT] = 'This is a test alert message $MNUM\n'.
  1389. 'Loaded language is $LANG\n'.
  1390. 'PHP version is $PHPVERS\n'.
  1391. 'FormMail version is $FM_VERS\n'.
  1392. 'Server type: $SERVER\n'.
  1393. '\n'.
  1394. 'DOCUMENT_ROOT: $DOCUMENT_ROOT\n'.
  1395. 'SCRIPT_FILENAME: $SCRIPT_FILENAME\n'.
  1396. 'PATH_TRANSLATED: $PATH_TRANSLATED\n'.
  1397. 'REAL_DOCUMENT_ROOT: $REAL_DOCUMENT_ROOT';
  1398. // MSG_NO_DEF_ALERT is displayed if you use the testalert feature
  1399. // and no DEF_ALERT setting has been provided.
  1400. // Parameters: none
  1401. $aMessages[MSG_NO_DEF_ALERT] = 'No DEF_ALERT value has been set.';
  1402. // MSG_TEST_SENT is displayed if when use the testalert feature
  1403. // Parameters: none
  1404. $aMessages[MSG_TEST_SENT] = 'Test message sent. Check your email.';
  1405. // MSG_TEST_FAILED is displayed if when use the testalert feature
  1406. // and the mail sending fails.
  1407. // Parameters: none
  1408. $aMessages[MSG_TEST_FAILED] = 'FAILED to send alert message. Check your '.
  1409. 'server error logs.';
  1410. // MSG_NO_DATA_PAGE is the page that's displayed if the user
  1411. // just opens the URL to FormMail directly.
  1412. // Parameters: none
  1413. $aMessages[MSG_NO_DATA_PAGE] = 'This URL is a Form submission program.\n'.
  1414. 'It appears the form is not working '.
  1415. 'correctly as there was no data found.\n'.
  1416. 'You\'re not supposed to browse to this '.
  1417. 'URL; it should be accessed from a form.';
  1418. // MSG_REQD_ERROR is displayed to the user as a default error
  1419. // message when they haven't supplied some required fields
  1420. // Parameters: none
  1421. $aMessages[MSG_REQD_ERROR] = 'The form required some values that you '.
  1422. 'did not seem to provide.';
  1423. // MSG_COND_ERROR is displayed to the user as a default error
  1424. // message when some form conditions have failed
  1425. // Parameters: none
  1426. $aMessages[MSG_COND_ERROR] = 'Some of the values you provided are not valid.';
  1427. // MSG_CRM_FAILURE is displayed to the user when submission
  1428. // to the CRM has failed.
  1429. // Parameters:
  1430. // $URL the URL that was used
  1431. // $DATA data returned from the CRM
  1432. $aMessages[MSG_CRM_FAILURE] = 'The form submission did not succeed due to '.
  1433. 'a CRM failure. URL was \'$URL\'. '.
  1434. 'Returned CRM data:\n$DATA';
  1435. // MSG_FOPTION_WARN is sent in an Alert message when the form
  1436. // uses the superseded SendMailFOption feature
  1437. // Parameters:
  1438. // $LINE line number for SENDMAIL_F_OPTION
  1439. $aMessages[MSG_FOPTION_WARN] = 'Warning: You\'ve used SendMailFOption in '.
  1440. '"mail_options" in your form. This has been '.
  1441. 'superseded with a configuration setting '.
  1442. 'inside formmail.php. Please update your '.
  1443. 'formmail.php configuration (look for '.
  1444. 'SENDMAIL_F_OPTION on line $LINE) and set '.
  1445. 'it to "true", then remove SendMailFOption '.
  1446. 'from your form(s).';
  1447. // MSG_NO_ACTIONS is sent in an Alert message when there is no
  1448. // action to perform or email address to send to
  1449. // Parameters: none
  1450. $aMessages[MSG_NO_ACTIONS] = 'The form has an internal error - no actions '.
  1451. 'or recipients were specified.';
  1452. // MSG_NO_RECIP is sent in an Alert message when there are no
  1453. // valid recipients to send to
  1454. // Parameters: none
  1455. $aMessages[MSG_NO_RECIP] = 'The form has an internal error - no valid '.
  1456. 'recipients were specified.';
  1457. // MSG_INV_EMAIL is sent in an Alert message when there are errors
  1458. // in the email addresses specified in the form
  1459. // Parameters:
  1460. // $ERRORS list of errors
  1461. $aMessages[MSG_INV_EMAIL] = 'Invalid email addresses were specified '.
  1462. 'in the form $MNUM:\n$ERRORS';
  1463. // MSG_FAILED_SEND is sent in an Alert message when the mail sending fails.
  1464. // Parameters: none
  1465. $aMessages[MSG_FAILED_SEND] = 'Failed to send email';
  1466. // MSG_ARESP_EMAIL is sent in an Alert message when
  1467. // no email address has been specified for an autoreponse
  1468. // Parameters: none
  1469. $aMessages[MSG_ARESP_EMAIL] = 'No "email" field was found. Autorespond '.
  1470. 'requires the submitter\'s email address.';
  1471. // MSG_ARESP_SUBJ is the default subject for the auto response email
  1472. // Parameters: none
  1473. $aMessages[MSG_ARESP_SUBJ] = 'Your form submission';
  1474. // MSG_LOG_NO_VERIMG is written to the auto respond log file
  1475. // if no VerifyImgString session variable was found
  1476. // Parameters: none
  1477. $aMessages[MSG_LOG_NO_VERIMG] = 'No VerifyImgString or turing_string in session, '.
  1478. 'no reverse CAPTCHA, no reCaptcha';
  1479. // MSG_ARESP_NO_AUTH is shown to the user
  1480. // if no VerifyImgString session variable was found
  1481. // Parameters: none
  1482. $aMessages[MSG_ARESP_NO_AUTH] = 'Failed to obtain authorization to send '.
  1483. 'you email. This is probably a fault on '.
  1484. 'the server.';
  1485. // MSG_LOG_NO_MATCH is written to the auto respond log file
  1486. // if the user's entry did not match the image verification
  1487. // Parameters: none
  1488. $aMessages[MSG_LOG_NO_MATCH] = 'User did not match image';
  1489. // MSG_LOG_RECAPTCHA is written to the auto respond log file
  1490. // if the reCaptcha process fails
  1491. // Parameters:
  1492. // ERR the reCaptcha error code
  1493. $aMessages[MSG_LOG_RECAPTCHA] = 'reCaptcha process failed ($ERR)';
  1494. // MSG_ARESP_NO_MATCH is shown to the user
  1495. // if the user's entry did not match the image verification
  1496. // Parameters: none
  1497. $aMessages[MSG_ARESP_NO_MATCH] = 'Your entry did not match the image';
  1498. // MSG_LOG_FAILED is written to the auto respond log file
  1499. // if the autoresponding failed
  1500. // Parameters: none
  1501. $aMessages[MSG_LOG_FAILED] = 'Failed';
  1502. // MSG_ARESP_FAILED is sent in an Alert message
  1503. // if the autoresponding failed
  1504. // Parameters: none
  1505. $aMessages[MSG_ARESP_FAILED] = 'Autoresponder failed';
  1506. // MSG_LOG_OK is written to the auto respond log file
  1507. // if the autoresponding succeeded
  1508. // Parameters: none
  1509. $aMessages[MSG_LOG_OK] = 'OK';
  1510. // MSG_THANKS_PAGE is the default page that's displayed if the
  1511. // submission is successful
  1512. // Parameters: none
  1513. $aMessages[MSG_THANKS_PAGE] = 'Thanks! We\'ve received your information '.
  1514. 'and, if it\'s appropriate, we\'ll be in '.
  1515. 'contact with you soon.';
  1516. // MSG_LOAD_MODULE is sent in an alert message if a module
  1517. // could not be loaded.
  1518. // Parameters:
  1519. // $FILE the file name
  1520. // $ERROR the error message
  1521. $aMessages[MSG_LOAD_MODULE] = 'Cannot load module from file \'$FILE\': $ERROR';
  1522. // MSG_LOAD_FMCOMPUTE is sent in an alert message if the form
  1523. // specifies at least one "fmcompute" field and the FMCompute
  1524. // module cannot be loaded.
  1525. // Parameters:
  1526. // $FILE the file name
  1527. // $ERROR the error message
  1528. $aMessages[MSG_LOAD_FMCOMPUTE] = 'Cannot load FMCompute module from file '.
  1529. '\'$FILE\': $ERROR';
  1530. // MSG_REGISTER_MODULE is sent in an alert message if a module
  1531. // could not register with FMCompute
  1532. // Parameters:
  1533. // $NAME the name of the module
  1534. // $ERROR the error message
  1535. $aMessages[MSG_REGISTER_MODULE] = 'Cannot register module $NAME with '.
  1536. 'FMCompute: $ERROR';
  1537. // MSG_COMP_PARSE is sent in an alert message if a parse error
  1538. // occurs in an fmcompute field
  1539. // Parameters:
  1540. // $CODE the code with an error
  1541. // $ERRORS the error messages
  1542. $aMessages[MSG_COMP_PARSE] = 'These parse errors occurred in the following '.
  1543. 'code:\n$ERRORS\n$CODE';
  1544. // MSG_COMP_REG_DATA is sent in an alert message if FormMail cannot
  1545. // register a data field with the FMCompute module
  1546. // Parameters:
  1547. // $NAME the field name
  1548. // $ERROR the error message
  1549. $aMessages[MSG_COMP_REG_DATA] = 'Failed to register data field \'$NAME\': '.
  1550. '$ERROR';
  1551. // MSG_COMP_ALERT is sent in an alert message if the FMCompute
  1552. // module has generated some alert messages.
  1553. // Parameters:
  1554. // $ALERTS the alerts
  1555. $aMessages[MSG_COMP_ALERT] = 'The following alert messages were reported '.
  1556. 'from the FMCompute module: $ALERTS';
  1557. // MSG_COMP_DEBUG is sent in an alert message if the FMCompute
  1558. // module has generated some debug messages.
  1559. // Parameters:
  1560. // $DEBUG the alerts
  1561. $aMessages[MSG_COMP_DEBUG] = 'The following debug messages were reported '.
  1562. 'from the FMCompute module: $DEBUG';
  1563. // MSG_COMP_EXEC is sent in an alert message if the FMCompute
  1564. // module has generated some error messages during execution
  1565. // Parameters:
  1566. // $ERRORS the errors
  1567. $aMessages[MSG_COMP_EXEC] = 'The following error messages were reported '.
  1568. 'from the FMCompute module: $ERRORS';
  1569. // MSG_TEMPL_ALERT is sent in an alert message if Advanced Template
  1570. // Processing has generated some alert messages.
  1571. // Parameters:
  1572. // $ALERTS the alerts
  1573. $aMessages[MSG_TEMPL_ALERT] = 'The following alert messages were reported '.
  1574. 'from the Advanced Template Processor: $ALERTS';
  1575. // MSG_TEMPL_DEBUG is sent in an alert message if Advanced Template
  1576. // Processing has generated some debug messages.
  1577. // Parameters:
  1578. // $DEBUG the alerts
  1579. $aMessages[MSG_TEMPL_DEBUG] = 'The following debug messages were reported '.
  1580. 'from the Advanced Template Processor: $DEBUG';
  1581. // MSG_TEMPL_PROC is sent in an alert message if Advanced Template Processing
  1582. // has generated some error messages during processing
  1583. // Parameters:
  1584. // $ERRORS the errors
  1585. $aMessages[MSG_TEMPL_PROC] = 'The following error messages were reported '.
  1586. 'from the Advanced Template Processor: $ERRORS';
  1587. // MSG_REG_FMCOMPUTE is sent in an Alert message when FormMail
  1588. // cannot register an external function with FMCompute.
  1589. // Parameters:
  1590. // FUNC the function that could not be registered
  1591. // ERROR the error message
  1592. $aMessages[MSG_REG_FMCOMPUTE] = 'Cannot register function "$FUNC" with '.
  1593. 'FMCompute: $ERROR';
  1594. // MSG_USER_ERRORS is shown as part of a user error when an FMCompute
  1595. // has called the "UserError" function one or more times.
  1596. // Parameters:
  1597. // NONE
  1598. $aMessages[MSG_USER_ERRORS] = 'One or more errors occurred in your form submission';
  1599. // MSG_CALL_PARAM_COUNT is sent in an alert when a call to a FormMail
  1600. // function from FMCompute has the wrong number of parameters
  1601. // Parameters:
  1602. // FUNC the function name
  1603. // COUNT the actual number of parameters passed
  1604. $aMessages[MSG_CALL_PARAM_COUNT] = 'FMCompute called FormMail function '.
  1605. '\'$FUNC\' with wrong number of '.
  1606. 'parameters: $COUNT';
  1607. // MSG_CALL_UNK_FUNC is sent in an alert when FMCompute calls an
  1608. // unknown FormMail function
  1609. // Parameters:
  1610. // FUNC the function name
  1611. $aMessages[MSG_CALL_UNK_FUNC] = 'FMCompute called unknown FormMail function '.
  1612. '\'$FUNC\'';
  1613. // MSG_SAVE_FILE is sent in an alert when saving a file to
  1614. // the server has failed
  1615. // Parameters:
  1616. // FILE the source file name (usually a temporary file name)
  1617. // DEST the destination file name
  1618. // ERR the error message
  1619. $aMessages[MSG_SAVE_FILE] = 'Failed to save file \'$FILE\' to \'$DEST\': $ERR';
  1620. // MSG_SAVE_FILE_EXISTS is sent as part of an alert when saving a file to
  1621. // the repository ($FILE_REPOSITORY) has failed because the file
  1622. // already exists and FILE_OVERWRITE is set to false.
  1623. // Parameters:
  1624. // FILE the destination file name
  1625. $aMessages[MSG_SAVE_FILE_EXISTS] = 'Cannot save file to repository as this would '.
  1626. 'overwrite \'$FILE\' and you have '.
  1627. 'set FILE_OVERWRITE to false.';
  1628. // MSG_EMPTY_ADDRESSES is sent as part of an alert when a number of empty
  1629. // email addresses have been specified in recipients, cc, or bcc
  1630. // *and* there are no valid addresses provided
  1631. // in the list
  1632. // Parameters:
  1633. // COUNT the number of empty addresses
  1634. $aMessages[MSG_EMPTY_ADDRESSES] = '$COUNT empty addresses';
  1635. // MSG_CALL_INVALID_PARAM is sent in an alert when a call to a FormMail
  1636. // function from FMCompute has an invalid parameter
  1637. // Parameters:
  1638. // FUNC the function name
  1639. // PARAM the parameter number
  1640. // CORRECT information about correct values
  1641. $aMessages[MSG_CALL_INVALID_PARAM] = 'FMCompute called FormMail function '.
  1642. '\'$FUNC\' with an invalid parameter '.
  1643. 'number $PARAM. Correct values are: $CORRECT';
  1644. // MSG_INI_PARSE_WARN is sent in an alert when the INI file
  1645. // may have a syntax error and cannot be parsed.
  1646. // Parameters:
  1647. // FILE the file name
  1648. $aMessages[MSG_INI_PARSE_WARN] = 'Warning: your INI file \'$FILE\' appears '.
  1649. 'to be empty. This may indicate a syntax error.';
  1650. // MSG_INI_PARSE_ERROR is shown as an error message when the INI file
  1651. // has a syntax error and cannot be parsed.
  1652. // Parameters:
  1653. // FILE the file name
  1654. $aMessages[MSG_INI_PARSE_ERROR] = 'The FormMail INI file \'$FILE\' has a syntax error';
  1655. // MSG_CHMOD is sent in an alert when changing the protection
  1656. // mode of a file to has failed
  1657. // Parameters:
  1658. // FILE the file name
  1659. // MODE the mode
  1660. // ERR the error message
  1661. $aMessages[MSG_CHMOD] = 'Failed to change protection mode of file \'$FILE\' '.
  1662. 'to $MODE: $ERR';
  1663. // MSG_VERIFY_MISSING is shown to the user image verification string
  1664. // was not found
  1665. // Parameters: none
  1666. $aMessages[MSG_VERIFY_MISSING] = 'Image verification string missing. This'.
  1667. ' is probably a fault on the server.';
  1668. // MSG_VERIFY_MATCH is shown to the user
  1669. // if the user's entry did not match the image verification for the
  1670. // imgverify option
  1671. // Parameters: none
  1672. $aMessages[MSG_VERIFY_MATCH] = 'Your entry did not match the image';
  1673. // MSG_RECAPTCHA_MATCH is shown to the user
  1674. // if using the reCaptcha system and there was an error
  1675. // Parameters:
  1676. // ERR the error code from the reCaptcha API
  1677. $aMessages[MSG_RECAPTCHA_MATCH] = 'reCaptcha verification failed ($ERR)';
  1678. // MSG_FILE_NAMES_INVALID is sent in an Alert message when
  1679. // a form's file_names setting has errors
  1680. // Parameters: none
  1681. // A list of errors is appended on separate lines
  1682. $aMessages[MSG_FILE_NAMES_INVALID] = 'Some file_names specifications are invalid $MNUM:\n';
  1683. // MSG_FILE_NAMES_NOT_FILE is sent in an Alert message when
  1684. // a form's file_names setting refers to a file field that doesn't
  1685. // exist
  1686. // Parameters:
  1687. // NAME the name of the file field that doesn't exist
  1688. $aMessages[MSG_FILE_NAMES_NOT_FILE] = 'Your file_names specification has '.
  1689. 'an error. \'$NAME\' is not the name '.
  1690. 'of a file upload field\n';
  1691. // MSG_NEXT_PLUS_GOOD is sent in an alert message if the form is
  1692. // ambiguous and specifies both "next_form" and "good_url" or
  1693. // "good_template"
  1694. // Parameters:
  1695. // $WHICH the "good_" field that was specified
  1696. $aMessages[MSG_NEXT_PLUS_GOOD] = 'The form has specified both "next_form" '.
  1697. 'and "$WHICH" fields - the action to '.
  1698. 'to perform is ambiguous';
  1699. // MSG_MULTIFORM is sent in an Alert message when a form tries
  1700. // to use a multi-form template, but templates have not been configured in
  1701. // formmail.php
  1702. // Parameters: none
  1703. $aMessages[MSG_MULTIFORM] = 'You must set either MULTIFORMDIR or MULTIFORMURL '.
  1704. 'in formmail.php before you can use '.
  1705. 'multi-page forms.';
  1706. // MSG_MULTIFORM_FAILED is sent in an Alert message
  1707. // when processing a multi-page form template has failed.
  1708. // Parameters:
  1709. // NAME the template name
  1710. $aMessages[MSG_MULTIFORM_FAILED] = 'Failed to process multi-page form template "$NAME"';
  1711. // MSG_NEED_THIS_FORM is sent in an Alert message
  1712. // when a multi-page form does not specify the "this_form" field.
  1713. // Parameters:
  1714. // none
  1715. $aMessages[MSG_NEED_THIS_FORM] = 'Multi-page forms require "this_form" field';
  1716. // MSG_NO_PHP_SELF is sent in an Alert message
  1717. // when FormMail requires the "PHP_SELF" server variable and PHP is not
  1718. // providing it.
  1719. // Parameters:
  1720. // none
  1721. $aMessages[MSG_NO_PHP_SELF] = 'PHP on the server is not providing "PHP_SELF"';
  1722. // MSG_RETURN_URL_INVALID is sent in an Alert message
  1723. // when "this_form" is not a valid return URL. This occurs for
  1724. // multi-page forms.
  1725. // Parameters:
  1726. // URL the invalid URL
  1727. $aMessages[MSG_RETURN_URL_INVALID] = 'Return URL "$URL" is not valid';
  1728. // MSG_GO_BACK is sent in an Alert message
  1729. // when "multi_go_back" has been submitted but this isn't part of a
  1730. // multi-page form.
  1731. // Parameters:
  1732. // none
  1733. $aMessages[MSG_GO_BACK] = 'Cannot "go back" if not in a multi-page form '.
  1734. 'sequence or at the first page of the form '.
  1735. 'sequence';
  1736. // MSG_OPEN_URL is sent in an Alert message when a URL cannot
  1737. // be opened.
  1738. // Parameters:
  1739. // URL the invalid URL
  1740. // ERROR error message
  1741. $aMessages[MSG_OPEN_URL] = 'Cannot open URL "$URL": $ERROR';
  1742. // MSG_CANNOT_RETURN is sent in an Alert message when an invalid return
  1743. // request is made in a multi-page form sequence.
  1744. // Parameters:
  1745. // TO the requested page index
  1746. // TOPINDEX the top page index
  1747. $aMessages[MSG_CANNOT_RETURN] = 'Cannot return to page $TO. The top page '.
  1748. 'index is $TOPINDEX';
  1749. // MSG_ATTACK_DETECTED is sent in an Alert message when an attack on
  1750. // the server has been detected
  1751. // Parameters:
  1752. // ATTACK name or description of the attack
  1753. // INFO more information about the attack
  1754. $aMessages[MSG_ATTACK_DETECTED] = 'Server attack "$ATTACK" detected. '.
  1755. 'Your server is safe as FormMail is '.
  1756. 'invulnerable to this attack. You can '.
  1757. 'disable these messages by setting '.
  1758. 'ALERT_ON_ATTACK_DETECTION to false '.
  1759. 'in FormMail\'s configuration section.'.
  1760. '\nMore information:\n$INFO';
  1761. // MSG_ATTACK_PAGE is the contents of the browser page displayed to the
  1762. // user when an attack is detected
  1763. // Parameters:
  1764. // SERVER the name of the server (website)
  1765. // USERINFO details of the error
  1766. $aMessages[MSG_ATTACK_PAGE] = 'Your form submission has been rejected '.
  1767. 'as it appears to be an abuse of our server ('.
  1768. '$SERVER).<br />'.
  1769. 'Our supplier of forms processing software has '.
  1770. 'provided <a href="http://www.tectite.com/serverabuse.php" '.
  1771. ' target="_blank">more information about this error</a>.<br /><br />'.
  1772. '$USERINFO';
  1773. // MSG_ATTACK_MIME_INFO is the contents of the INFO parameter
  1774. // to the MSG_ATTACK_DETECTED message for the MIME attack
  1775. // Parameters:
  1776. // FLD name of the field
  1777. // CONTENT the invalid content found in the field
  1778. $aMessages[MSG_ATTACK_MIME_INFO] = 'The field "$FLD" contained invalid '.
  1779. 'content "$CONTENT"';
  1780. // MSG_ATTACK_DUP_INFO is the contents of the INFO parameter
  1781. // to the MSG_ATTACK_DETECTED message for the Duplicate Data attack
  1782. // Parameters:
  1783. // FLD1 name of the first field
  1784. // FLD2 name of the second field
  1785. $aMessages[MSG_ATTACK_DUP_INFO] = 'The fields "$FLD1" and "$FLD2" contained '.
  1786. 'duplicate data';
  1787. // MSG_ATTACK_SPEC_INFO is the contents of the INFO parameter
  1788. // to the MSG_ATTACK_DETECTED message for the Special Field attack
  1789. // Parameters:
  1790. // FLD name of the special field
  1791. $aMessages[MSG_ATTACK_SPEC_INFO] = 'Special field "$FLD" contained an email address';
  1792. // MSG_ATTACK_MANYURL_INFO is the contents of the INFO parameter
  1793. // to the MSG_ATTACK_DETECTED message for the Many URLs attack
  1794. // Parameters:
  1795. // FLD name of the field
  1796. // NUM number of URLs detected
  1797. $aMessages[MSG_ATTACK_MANYURL_INFO] = 'Field "$FLD" contained $NUM URLs';
  1798. // MSG_ATTACK_MANYFIELDS_INFO is the contents of the INFO parameter
  1799. // to the MSG_ATTACK_DETECTED message for the Many Fields with URLs
  1800. // attack
  1801. // Parameters:
  1802. // NUM number of fields detected with URLs
  1803. // FLDS list of fields with URLs in them
  1804. $aMessages[MSG_ATTACK_MANYFIELDS_INFO] = '$NUM fields contained URLs: $FLDS';
  1805. // MSG_REV_CAP is an error regarding the setting of ATTACK_DETECTION_REVERSE_CAPTCHA
  1806. // Parameters: none
  1807. $aMessages[MSG_REV_CAP] = 'ATTACK_DETECTION_REVERSE_CAPTCHA is not set correctly, '.
  1808. 'and will be ignored. Please refer to the documentation '.
  1809. 'to make the correct setting.';
  1810. // MSG_ATTACK_REV_CAP_INFO is the contents of the INFO parameter
  1811. // to the MSG_ATTACK_DETECTED message for the Reverse Captcha attack
  1812. // detection
  1813. // Parameters:
  1814. // FLD name of the field
  1815. // CONTENT the invalid content found in the field
  1816. $aMessages[MSG_ATTACK_REV_CAP_INFO] = 'The field "$FLD" contained unexpected '.
  1817. 'content "$CONTENT".';
  1818. // MSG_ATTACK_JUNK_INFO is the contents of the INFO parameter
  1819. // to the MSG_ATTACK_DETECTED message for the JUNK attack
  1820. // Parameters:
  1821. // FLD name of the field
  1822. // JUNK the junk that was found
  1823. $aMessages[MSG_ATTACK_JUNK_INFO] = 'The field "$FLD" contained junk '.
  1824. 'data "$JUNK"';
  1825. // MSG_ARESP_EMPTY is an alert message sent when
  1826. // an autoresponse template or file is empty
  1827. // Parameters:
  1828. // TYPE the type of autoreponse requested
  1829. $aMessages[MSG_ARESP_EMPTY] = 'The autoresponse is empty. The form '.
  1830. 'requested $TYPE';
  1831. // MSG_NEED_SCRATCH_PAD is an alert message when processing requires
  1832. // SCRATCH_PAD configuration for file upload processing. This occurs
  1833. // when you upload files in pages of a multi page form sequence.
  1834. // Parameters:
  1835. // none
  1836. $aMessages[MSG_NEED_SCRATCH_PAD] = 'You need to set SCRATCH_PAD in the '.
  1837. 'configuration section to process '.
  1838. 'uploaded files.';
  1839. // MSG_OPEN_SCRATCH_PAD is an alert message when the SCRATCH_PAD
  1840. // directory cannot be opened for cleanup.
  1841. // Parameters:
  1842. // DIR name of the directory
  1843. // ERR more error information
  1844. $aMessages[MSG_OPEN_SCRATCH_PAD] = 'Cannot open SCRATCH_PAD directory '.
  1845. '"$DIR". Open failed: $ERR';
  1846. // MSG_NO_NEXT_NUM_FILE is an alert message when a form tries to
  1847. // use the %nextnum% derivation feature but you haven't
  1848. // setup FormMail's configuration correctly.
  1849. // Parameters:
  1850. // none
  1851. $aMessages[MSG_NO_NEXT_NUM_FILE] = 'You cannot use the %nextnum% feature: '.
  1852. 'you have not configured NEXT_NUM_FILE';
  1853. // MSG_NEXT_NUM_FILE is an alert message when a form tries to
  1854. // use the %nextnum% derivation feature but the next number file cannot
  1855. // be processed.
  1856. // Parameters:
  1857. // FILE name of the file
  1858. // ACT action
  1859. // ERR more error information
  1860. $aMessages[MSG_NEXT_NUM_FILE] = 'Cannot $ACT next number file '.
  1861. '\'$FILE\': $ERR';
  1862. // MSG_MULTI_UPLOAD is an alert message when processing of uploaded
  1863. // fails during a multi-page form sequence
  1864. // Parameters:
  1865. // none
  1866. $aMessages[MSG_MULTI_UPLOAD] = 'File upload processing failed during '.
  1867. 'multi-page form processing.';
  1868. // MSG_URL_PARSE is an error message when a URL to be opened
  1869. // cannot be parsed
  1870. // Parameters:
  1871. // none
  1872. $aMessages[MSG_URL_PARSE] = 'Failed to parse URL';
  1873. // MSG_URL_SCHEME is an error message when a URL to be opened
  1874. // has an unsupported "scheme" value
  1875. // Parameters:
  1876. // SCHEME the scheme that was seen
  1877. $aMessages[MSG_URL_SCHEME] = 'Unsupported URL scheme "$SCHEME"';
  1878. // MSG_SOCKET is an error message when opening a socket for a URL
  1879. // fails
  1880. // Parameters:
  1881. // ERRNO the error code
  1882. // ERRSTR the error string
  1883. // PHPERR the value of $php_errormsg
  1884. $aMessages[MSG_SOCKET] = 'Socket error $ERRNO: $ERRSTR: $PHPERR';
  1885. // MSG_GETURL_OPEN is an error message when the web server reports
  1886. // a failure on opening a URL
  1887. // Parameters:
  1888. // STATUS the HTTP status value (number + string)
  1889. $aMessages[MSG_GETURL_OPEN] = 'Open URL failed: $STATUS';
  1890. // MSG_RESOLVE is an error message when a host name cannot be
  1891. // resolved to an IP address
  1892. // Parameters:
  1893. // NAME the host name that could not be resolved
  1894. $aMessages[MSG_RESOLVE] = 'Cannot resolve host name "$NAME"';
  1895. // MSG_FORM_OK is the page title for the default
  1896. // "thank you" page
  1897. // Parameters:
  1898. // none
  1899. $aMessages[MSG_FORM_OK] = 'Form Submission Succeeded';
  1900. // MSG_FORM_ERROR is the page title for default
  1901. // error pages
  1902. // Parameters:
  1903. // none
  1904. $aMessages[MSG_FORM_ERROR] = 'Form Submission Error';
  1905. // MSG_GET_DISALLOWED is the message shown when GET method is used
  1906. // but has been disabled.
  1907. // Parameters:
  1908. // none
  1909. $aMessages[MSG_GET_DISALLOWED] = 'GET method has been disabled. Forms must use '.
  1910. 'the POST method. Alternatively, reconfigure '.
  1911. 'FormMail to allow the GET method.';
  1912. // MSG_FILE_UPLOAD_ERRn are the error messages corresponding to the
  1913. // PHP file upload error code n.
  1914. // Parameters:
  1915. // none
  1916. $aMessages[MSG_FILE_UPLOAD_ERR1] = 'The uploaded file exceeds the upload_max_filesize directive in php.ini.';
  1917. $aMessages[MSG_FILE_UPLOAD_ERR2] = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.';
  1918. $aMessages[MSG_FILE_UPLOAD_ERR3] = 'The uploaded file was only partially uploaded.';
  1919. $aMessages[MSG_FILE_UPLOAD_ERR4] = 'No file was uploaded.';
  1920. $aMessages[MSG_FILE_UPLOAD_ERR6] = 'Missing a temporary folder.';
  1921. $aMessages[MSG_FILE_UPLOAD_ERR7] = 'Failed to write file to disk.';
  1922. $aMessages[MSG_FILE_UPLOAD_ERR8] = 'File upload stopped by extension.';
  1923. // MSG_FILE_UPLOAD_ERR_UNK is displayed when an unknown error code
  1924. // is provided by PHP for a file upload
  1925. // Parameters:
  1926. // ERRNO the error code
  1927. $aMessages[MSG_FILE_UPLOAD_ERR_UNK] = 'Unknown file upload error code $ERRNO';
  1928. // MSG_FILE_UPLOAD_SIZE is displayed when an uploaded file exceeds
  1929. // the configured maximum size
  1930. // Parameters:
  1931. // NAME the uploaded file's name
  1932. // SIZE the size of the uploaded file
  1933. // MAX the maximum size that was exceeded
  1934. $aMessages[MSG_FILE_UPLOAD_SIZE] = 'Uploaded file "$NAME" is too big ('.
  1935. '$SIZE bytes). The maximum permitted '.
  1936. 'size is $MAX kilobytes.';
  1937. // MSG_DER_FUNC_ERROR is sent in an Alert message when
  1938. // a form uses a derive_fields function that's
  1939. // formatted incorrectly
  1940. // Parameters:
  1941. // $SPEC the invalid value specification
  1942. // $MSG a message describing the error or providing an example
  1943. $aMessages[MSG_DER_FUNC_ERROR] = 'derive_fields: invalid function specification '.
  1944. '"$SPEC": $MSG';
  1945. // MSG_DER_FUNC_SIZE_FMT describes the right syntax for the "size" function
  1946. // Parameters:
  1947. // none
  1948. $aMessages[MSG_DER_FUNC_SIZE_FMT] = '"size" function requires this format: '.
  1949. 'size(file_field)';
  1950. // MSG_DER_FUNC_IF_FMT describes the right syntax for the "if" function
  1951. // Parameters:
  1952. // none
  1953. $aMessages[MSG_DER_FUNC_IF_FMT] = '"if" function requires this format: '.
  1954. 'if(field;spec;spec)';
  1955. // MSG_DER_FUNC_NEXTNUM_FMT describes the right syntax for the "nextnum" function
  1956. // Parameters:
  1957. // none
  1958. $aMessages[MSG_DER_FUNC_NEXTNUM_FMT] = '"nextnum" function requires this format: '.
  1959. 'nextnum(pad) or nextnum(pad;base). pad and base '.
  1960. 'must be numbers. base must be 2 to 36 inclusive';
  1961. // MSG_DER_FUNC_EXT_FMT describes the right syntax for the "ext" function
  1962. // Parameters:
  1963. // none
  1964. $aMessages[MSG_DER_FUNC_EXT_FMT] = '"ext" function requires this format: '.
  1965. 'ext(file_field)';
  1966. // MSG_DER_FUNC1_FMT describes the right syntax for a function
  1967. // requiring one parameter
  1968. // Parameters:
  1969. // FUNC name of the function
  1970. $aMessages[MSG_DER_FUNC1_FMT] = '"$FUNC" function requires this format: '.
  1971. '$FUNC(fieldname)';
  1972. // MSG_USER_ATTACK_JUNK is a message shown to the user when a junk
  1973. // attack has been detected
  1974. // Parameters:
  1975. // INPUT the data the user input
  1976. $aMessages[MSG_USER_ATTACK_JUNK] = 'The following input looks like a junk attack '.
  1977. 'on our server. Please avoid scientific '.
  1978. 'or technical terms with long sequences '.
  1979. 'of consonants or vowels: $INPUT';
  1980. // MSG_USER_ATTACK_REV_CAP is a message shown to the user when a reverse
  1981. // captcha attack has been detected
  1982. // Parameters:
  1983. // none
  1984. $aMessages[MSG_USER_ATTACK_REV_CAP] = 'Your input looks like an automated spambot '.
  1985. 'attacking our server. Some automatic form '.
  1986. 'fillers can trigger this detection. Try '.
  1987. 'filling in our form manually. If you use the '.
  1988. 'back button to go back, make sure you '.
  1989. 'refresh the page before trying again.';
  1990. // MSG_USER_ATTACK_DUP is a message shown to the user when a duplicate
  1991. // data attack has been detected
  1992. // Parameters:
  1993. // none
  1994. $aMessages[MSG_USER_ATTACK_DUP] = 'You have input the same information in '.
  1995. 'several fields in the form. Please '.
  1996. 're-submit the form without duplication';
  1997. // MSG_USER_ATTACK_MANY_URLS is a message shown to the user when a many urls
  1998. // attack has been detected
  1999. // Parameters:
  2000. // none
  2001. $aMessages[MSG_USER_ATTACK_MANY_URLS] = 'Your input includes a number of URLs. '.
  2002. 'This server has been configured to reject '.
  2003. 'form submissions with too many URLs. '.
  2004. 'Please re-submit the form without URLs or '.
  2005. 'with fewer URLs.';
  2006. // MSG_USER_ATTACK_MANY_URL_FIELDS is a message shown to the user when a many urls
  2007. // attack has been detected
  2008. // Parameters:
  2009. // none
  2010. $aMessages[MSG_USER_ATTACK_MANY_URL_FIELDS] = $aMessages[MSG_USER_ATTACK_MANY_URLS];
  2011. } // <A NAME="BuiltinMessages"> Jump to: <A HREF="#MessageNumbers">
  2012. //
  2013. // If the form submission was using the GET method, switch to the
  2014. // GET vars instead of the POST vars
  2015. //
  2016. if (isset($aServerVars["REQUEST_METHOD"]) && $aServerVars["REQUEST_METHOD"] === "GET")
  2017. {
  2018. $bIsGetMethod = true;
  2019. if ($ALLOW_GET_METHOD)
  2020. {
  2021. if ($bUseOldVars)
  2022. $aFormVars = &$HTTP_GET_VARS;
  2023. else
  2024. $aFormVars = &$_GET;
  2025. }
  2026. elseif (($bUseOldVars && count($HTTP_GET_VARS) > 0) || (!$bUseOldVars && count($_GET) > 0))
  2027. $bHasGetData = true;
  2028. }
  2029. //
  2030. // Load the default language, and then override with an optional language file.
  2031. //
  2032. function LoadLanguage()
  2033. {
  2034. LoadBuiltinLanguage();
  2035. LoadLanguageFile();
  2036. }
  2037. //
  2038. // To return the value of a string or empty string if not set.
  2039. //
  2040. function CheckString($ss)
  2041. {
  2042. return (isset($ss) ? $ss : "");
  2043. }
  2044. $aGetMessageSubstituteErrors = array();
  2045. $aGetMessageSubstituteFound = array();
  2046. $bGetMessageSubstituteNoErrors = false;
  2047. //
  2048. // Worker function for GetMessage's preg_replace_callback calls.
  2049. // Returns the value of the matched variable name.
  2050. // Variables are searched for in the global $aGetMessageValues.
  2051. // If no such variable exists, an empty string is returned and the
  2052. // global variable $aGetMessageSubstituteErrors lists the missing names.
  2053. //
  2054. function GetMessageSubstituteParam($a_matches)
  2055. {
  2056. global $aGetMessageValues,$aGetMessageSubstituteErrors;
  2057. global $aGetMessageSubstituteFound,$bGetMessageSubstituteNoErrors;
  2058. $s_name = $a_matches[1];
  2059. $aGetMessageSubstituteFound[] = $s_name;
  2060. $s_value = "";
  2061. if (isset($aGetMessageValues[$s_name]))
  2062. $s_value = $aGetMessageValues[$s_name];
  2063. elseif ($bGetMessageSubstituteNoErrors)
  2064. $s_value = '$'.$s_name;
  2065. else
  2066. $aGetMessageSubstituteErrors[] = $s_name;
  2067. return ($s_value);
  2068. }
  2069. //
  2070. // Returns message text from a message number, with optional parameters.
  2071. //
  2072. function GetMessage($i_msg_num,$a_params = array(),
  2073. $b_show_mnum = true,$b_no_errors = false)
  2074. {
  2075. global $aMessages,$sLangID,$bShowMesgNumbers;
  2076. if (!isset($aMessages[$i_msg_num]))
  2077. {
  2078. SendAlert("Unknown Message Number $i_msg_num was used",false,true);
  2079. $s_text = "<UNKNOWN MESSAGE NUMBER>";
  2080. }
  2081. else
  2082. $s_text = $aMessages[$i_msg_num];
  2083. $s_mno = $bShowMesgNumbers ? "[M$i_msg_num]" : "";
  2084. $s_orig_text = $s_text;
  2085. //
  2086. // substitute parameters; only works with PHP version 4.0.5 or later
  2087. //
  2088. if (strpos($s_text,'$') !== false)
  2089. {
  2090. global $aGetMessageValues,$aGetMessageSubstituteErrors;
  2091. global $aGetMessageSubstituteFound,$bGetMessageSubstituteNoErrors;
  2092. $aGetMessageSubstituteErrors = array();
  2093. $aGetMessageSubstituteFound = array();
  2094. $aGetMessageValues = HTMLEntitiesArray($a_params,true);
  2095. $bGetMessageSubstituteNoErrors = $b_no_errors;
  2096. $aGetMessageValues["MNUM"] = $s_mno; // add the message number
  2097. //
  2098. // search for words in this form:
  2099. // $word
  2100. // where word begins with an alphabetic character and
  2101. // consists of alphanumeric and underscore
  2102. //
  2103. $s_text = preg_replace_callback('/\$([a-z][a-z0-9_]*)/i',
  2104. 'GetMessageSubstituteParam',$s_text);
  2105. if (count($aGetMessageSubstituteErrors) > 0)
  2106. SendAlert("Message Number $i_msg_num ('$s_orig_text') in language $sLangID ".
  2107. "specified the following unsupported parameters: ".
  2108. implode(',',$aGetMessageSubstituteErrors));
  2109. if (!in_array("MNUM",$aGetMessageSubstituteFound))
  2110. //
  2111. // append the message number
  2112. //
  2113. $s_text .= $b_show_mnum ? " $s_mno" : "";
  2114. }
  2115. else
  2116. //
  2117. // append the message number
  2118. //
  2119. $s_text .= $b_show_mnum ? " $s_mno" : "";
  2120. //
  2121. // replace '\n' sequences with new lines
  2122. //
  2123. return (str_replace('\n',"\n",$s_text));
  2124. }
  2125. //
  2126. // Check for old version of PHP - die if too old.
  2127. //
  2128. function IsOldVersion(&$a_this_version)
  2129. {
  2130. $a_modern = array(4,1,0); // versions prior to this are "old" - "4.1.0"
  2131. $s_req_string = "4.0.5"; // version 4.0.5 of PHP is required from
  2132. // FormMail 5.00 onward (because we use
  2133. // preg_replace_callback for all messages to
  2134. // support languages other than English)
  2135. $a_too_old = explode(".",$s_req_string);
  2136. $i_cannot_use = ($a_too_old[0] * 10000) +
  2137. ($a_too_old[1] * 100) +
  2138. $a_too_old[2];
  2139. $s_vers_string = phpversion();
  2140. $a_this_version = explode(".",$s_vers_string);
  2141. $i_this_num = ($a_this_version[0] * 10000) +
  2142. ($a_this_version[1] * 100) +
  2143. $a_this_version[2];
  2144. if ($i_this_num <= $i_cannot_use)
  2145. die(GetMessage(MSG_SCRIPT_VERSION,array("PHPREQ"=>$s_req_string,
  2146. "PHPVERS"=>$s_vers_string)));
  2147. $i_modern_num = ($a_modern[0] * 10000) +
  2148. ($a_modern[1] * 100) +
  2149. $a_modern[2];
  2150. return ($i_this_num < $i_modern_num);
  2151. }
  2152. //
  2153. // Check if the server is Windows
  2154. //
  2155. function IsServerWindows()
  2156. {
  2157. static $bGotAnswer = false;
  2158. static $bAnswer;
  2159. if (!$bGotAnswer)
  2160. {
  2161. if ((isset($_ENV["OS"]) && stristr($_ENV["OS"],"windows") !== false) ||
  2162. (isset($_SERVER["PATH"]) && stristr($_SERVER["PATH"],"winnt") !== false) ||
  2163. (isset($_SERVER["PATH"]) && stristr($_SERVER["PATH"],"windows") !== false) ||
  2164. (isset($_SERVER["SystemRoot"]) && stristr($_SERVER["SystemRoot"],"winnt") !== false) ||
  2165. (isset($_ENV["SystemRoot"]) && stristr($_ENV["SystemRoot"],"winnt") !== false) ||
  2166. (isset($_SERVER["SystemRoot"]) && stristr($_SERVER["SystemRoot"],"windows") !== false) ||
  2167. (isset($_ENV["SystemRoot"]) && stristr($_ENV["SystemRoot"],"windows") !== false) ||
  2168. (isset($_SERVER["Path"]) && stristr($_SERVER["Path"],"windows") !== false))
  2169. $bAnswer = true;
  2170. else
  2171. $bAnswer = false;
  2172. $bGotAnswer = true;
  2173. }
  2174. return ($bAnswer);
  2175. }
  2176. //
  2177. // To return a temporary file name from $SCRATCH_PAD
  2178. //
  2179. function GetScratchPadFile($s_prefix)
  2180. {
  2181. global $SCRATCH_PAD;
  2182. switch (substr($SCRATCH_PAD,-1))
  2183. {
  2184. case '/':
  2185. case '\\':
  2186. $s_dir = substr($SCRATCH_PAD,0,-1);
  2187. break;
  2188. default:
  2189. $s_dir = $SCRATCH_PAD;
  2190. break;
  2191. }
  2192. //
  2193. // Ideally, we could use tempnam. But,
  2194. // tempnam is system dependent and might not use the
  2195. // SCRATCH_PAD directory even if we tell it to.
  2196. // So, we'll force the file into SCRATCH_PAD.
  2197. //
  2198. // Note that we do *not* create the file, even though tempnam
  2199. // does create it in PHP version 4.0.3 and above. (The reason is
  2200. // we can't guarantee a non-race condition anyway.)
  2201. //
  2202. do
  2203. {
  2204. $i_rand = mt_rand(0,16777215); // 16777215 is FFFFFF in hex
  2205. $s_name = $SCRATCH_PAD."/".$s_prefix.sprintf("%06X",$i_rand);
  2206. }
  2207. while (file_exists($s_name));
  2208. return ($s_name);
  2209. }
  2210. //
  2211. // To return a temporary file name.
  2212. //
  2213. function GetTempName($s_prefix)
  2214. {
  2215. global $SCRATCH_PAD;
  2216. if (isset($SCRATCH_PAD) && !empty($SCRATCH_PAD))
  2217. $s_name = GetScratchPadFile($s_prefix);
  2218. else
  2219. $s_name = tempnam("/tmp",$s_prefix);
  2220. return ($s_name);
  2221. }
  2222. //
  2223. // To find a directory on the server for temporary files.
  2224. //
  2225. function GetTempDir()
  2226. {
  2227. $s_name = GetTempName("fm");
  2228. if (file_exists($s_name))
  2229. unlink($s_name);
  2230. $s_dir = dirname($s_name);
  2231. return ($s_dir);
  2232. }
  2233. //
  2234. // Returns true if the PHP version is at or later than the string specified
  2235. // (can't use "version_compare" before 4.1.0).
  2236. //
  2237. function IsPHPAtLeast($s_vers)
  2238. {
  2239. global $aPHPVERSION;
  2240. $a_test_version = explode(".",$s_vers);
  2241. if (count($a_test_version) < 3)
  2242. return (false);
  2243. return ($aPHPVERSION[0] > $a_test_version[0] ||
  2244. ($aPHPVERSION[0] == $a_test_version[0] &&
  2245. ($aPHPVERSION[1] > $a_test_version[1] ||
  2246. $aPHPVERSION[1] == $a_test_version[1] &&
  2247. $aPHPVERSION[2] >= $a_test_version[2])));
  2248. }
  2249. define('DEBUG',false); // for production
  2250. //define('DEBUG',true); // for development and debugging
  2251. define('RFCLINELEN',76); // recommend maximum line length from RFC 2822
  2252. //
  2253. // The user agent string to use when opening URLs
  2254. //
  2255. $sUserAgent = "FormMail/$FM_VERS (from www.tectite.com)";
  2256. if (DEBUG)
  2257. {
  2258. error_reporting(E_ALL); // trap everything!
  2259. if (IsPHPAtLeast("5.0.0"))
  2260. ini_set("display_errors","stdout");
  2261. else
  2262. ini_set("display_errors","1");
  2263. ini_set("display_startup_errors","1");
  2264. assert_options(ASSERT_ACTIVE,true);
  2265. assert_options(ASSERT_BAIL,true);
  2266. LoadLanguage();
  2267. }
  2268. else
  2269. {
  2270. $iOldLevel = error_reporting(E_ALL ^ E_WARNING);
  2271. LoadLanguage();
  2272. //
  2273. // report everyting except warnings and notices
  2274. //
  2275. error_reporting(E_ALL ^ E_WARNING ^ E_NOTICE);
  2276. }
  2277. function SetRealDocumentRoot()
  2278. {
  2279. global $aServerVars,$REAL_DOCUMENT_ROOT;
  2280. if (isset($aServerVars['SCRIPT_FILENAME']))
  2281. $REAL_DOCUMENT_ROOT = $aServerVars['SCRIPT_FILENAME'];
  2282. elseif (isset($aServerVars['PATH_TRANSLATED']))
  2283. $REAL_DOCUMENT_ROOT = $aServerVars['PATH_TRANSLATED'];
  2284. else
  2285. $REAL_DOCUMENT_ROOT = "";
  2286. //
  2287. // look for 'www' or 'public_html' and strip back to that if found,
  2288. // otherwise just get the directory name
  2289. //
  2290. if (($i_pos = strpos($REAL_DOCUMENT_ROOT,"/www/")) !== false)
  2291. $REAL_DOCUMENT_ROOT = substr($REAL_DOCUMENT_ROOT,0,$i_pos+4);
  2292. elseif (($i_pos = strpos($REAL_DOCUMENT_ROOT,"/public_html/")) !== false)
  2293. $REAL_DOCUMENT_ROOT = substr($REAL_DOCUMENT_ROOT,0,$i_pos+12);
  2294. elseif (!empty($REAL_DOCUMENT_ROOT))
  2295. $REAL_DOCUMENT_ROOT = dirname($REAL_DOCUMENT_ROOT);
  2296. elseif (isset($aServerVars['DOCUMENT_ROOT']) &&
  2297. !empty($aServerVars['DOCUMENT_ROOT']))
  2298. $REAL_DOCUMENT_ROOT = $aServerVars['DOCUMENT_ROOT'];
  2299. }
  2300. //
  2301. // Hook system: before initialization (but after configuration)
  2302. //
  2303. if ($HOOK_DIR !== "")
  2304. if (!@include("$HOOK_DIR/fmhookpreinit.inc.php"))
  2305. @include("$HOOK_DIR/fmhookpreinit.inc");
  2306. if (!empty($SESSION_NAME))
  2307. session_name($SESSION_NAME);
  2308. //
  2309. // Session data access
  2310. //
  2311. function GetSession($s_name)
  2312. {
  2313. global $bUseOldVars,$HTTP_SESSION_VARS;
  2314. if ($bUseOldVars)
  2315. return (isset($HTTP_SESSION_VARS) ? $HTTP_SESSION_VARS[$s_name] : null);
  2316. else
  2317. return (isset($_SESSION) ? $_SESSION[$s_name] : null);
  2318. }
  2319. //
  2320. // Session data isset
  2321. //
  2322. function IsSetSession($s_name)
  2323. {
  2324. global $bUseOldVars,$HTTP_SESSION_VARS;
  2325. if ($bUseOldVars)
  2326. return (isset($HTTP_SESSION_VARS) && isset($HTTP_SESSION_VARS[$s_name]));
  2327. else
  2328. return (isset($_SESSION) && isset($_SESSION[$s_name]));
  2329. }
  2330. //
  2331. // Session data setting
  2332. //
  2333. function SetSession($s_name,$m_value)
  2334. {
  2335. global $bUseOldVars,$HTTP_SESSION_VARS;
  2336. if ($bUseOldVars)
  2337. $HTTP_SESSION_VARS[$s_name] = $m_value;
  2338. else
  2339. $_SESSION[$s_name] = $m_value;
  2340. }
  2341. //
  2342. // Session data un-setting
  2343. //
  2344. function UnsetSession($s_name)
  2345. {
  2346. global $bUseOldVars,$HTTP_SESSION_VARS;
  2347. if ($bUseOldVars)
  2348. {
  2349. $HTTP_SESSION_VARS[$s_name] = null;
  2350. unset($HTTP_SESSION_VARS[$s_name]);
  2351. }
  2352. else
  2353. {
  2354. $_SESSION[$s_name] = null;
  2355. unset($_SESSION[$s_name]);
  2356. }
  2357. }
  2358. function ZapSession()
  2359. {
  2360. global $aSessionVarNames;
  2361. if (DESTROY_SESSION)
  2362. {
  2363. if (session_id() != '')
  2364. session_destroy();
  2365. }
  2366. else
  2367. {
  2368. foreach ($aSessionVarNames as $s_var_name)
  2369. UnsetSession($s_var_name);
  2370. }
  2371. }
  2372. $bReverseCaptchaCompleted = false; // records whether ATTACK_DETECTION_REVERSE_CAPTCHA has been completed successfully
  2373. session_start();
  2374. //
  2375. // This array lists the private variables used by FormMail.
  2376. // We use the names here to cleanup the session when FormMail has
  2377. // finished its processing.
  2378. //
  2379. $aSessionVarNames = array("FormError","FormErrorInfo","FormErrorCode",
  2380. "FormErrorItems","FormData","FormIsUserError",
  2381. "FormAlerted","FormSavedFiles","FormIndex",
  2382. "FormList","FormKeep","VerifyImgString",
  2383. "turing_string");
  2384. UnsetSession("FormError"); // start with no error
  2385. UnsetSession("FormErrorInfo"); // start with no error
  2386. UnsetSession("FormErrorCode"); // start with no error
  2387. UnsetSession("FormErrorItems"); // start with no error
  2388. UnsetSession("FormData"); // start with no data
  2389. UnsetSession("FormIsUserError"); // start with no data
  2390. UnsetSession("FormAlerted"); // start with no data
  2391. //
  2392. // Note that HTTP_REFERER is easily spoofed, so there's no point in
  2393. // using it for security.
  2394. //
  2395. //
  2396. // SPECIAL_FIELDS is the list of fields that formmail.php looks for to
  2397. // control its operation
  2398. //
  2399. $SPECIAL_FIELDS = array(
  2400. "email", // email address of the person who filled in the form
  2401. "realname", // the real name of the person who filled in the form
  2402. "recipients", // comma-separated list of email addresses to which we'll send the results
  2403. "cc", // comma-separated list of email addresses to which we'll CC the results
  2404. "bcc", // comma-separated list of email addresses to which we'll BCC the results
  2405. "replyto", // comma-separated list of email addresses to whom replies should be sent
  2406. "required", // comma-separated list of fields that must be found in the input
  2407. "conditions", // complex condition tests
  2408. "fmcompute", // computations
  2409. "fmmodules", // list of modules required
  2410. "fmmode", // mode of operation
  2411. "mail_options", // comma-separated list of options
  2412. "good_url", // URL to go to on success
  2413. "good_template",// template file to display on success
  2414. "bad_url", // URL to go to on error
  2415. "bad_template", // template file to display on error
  2416. "template_list_sep", // separator when expanding lists in templates
  2417. "this_form", // the URL of the form (can be used by bad_url)
  2418. "subject", // subject for the email
  2419. "env_report", // comma-separated list of environment variables to report
  2420. "filter", // a supported filter to use
  2421. "filter_options",// options for using the filter
  2422. "filter_fields",// list of fields to filter (default is to filter all fields)
  2423. "filter_files", // list of file fields to filter (default is to filter no file fields)
  2424. "logfile", // log file to write to
  2425. "csvfile", // file to write CSV records to
  2426. "csvcolumns", // columns to save in the csvfile
  2427. "crm_url", // URL for sending data to the CRM; note that the
  2428. // value must have a valid prefix specified in TARGET_URLS
  2429. "crm_spec", // CRM specification (field mapping)
  2430. "crm_options", // comma-separated list of options to control CRM processing
  2431. "derive_fields", // a list of fields to derive from other fields
  2432. "file_names", // specifies names for files being uploaded
  2433. "autorespond", // specification for auto-responding
  2434. "arverify", // verification field to allow auto-responding
  2435. "imgverify", // verification field to allow submission
  2436. "multi_start", // set this field on the first page of a multi-page form sequence
  2437. "multi_keep", // set this field on the pages of a multi-page form sequence
  2438. // to the list of fields that should be kept when moving
  2439. // forward after going backwards
  2440. "next_form", // next form name or empty for last form
  2441. "multi_go_back",// this field should be set when the user clicks the
  2442. // back button or link in a multi-page form sequence
  2443. "alert_to", // email address to send alerts (errors) to
  2444. //
  2445. // fields for reCaptcha implementation
  2446. //
  2447. "recaptcha_response_field", // verification field to allow submission
  2448. "recaptcha_challenge_field", // challenge field
  2449. );
  2450. //
  2451. // $SPECIAL_MULTI is the list of fields from $SPECIAL_FIELDS that can
  2452. // have multiple values, for example:
  2453. // name="conditions1"
  2454. // name="conditions2"
  2455. //
  2456. $SPECIAL_MULTI = array(
  2457. "conditions",
  2458. "fmcompute",
  2459. );
  2460. //
  2461. // $SPECIAL_ARRAYS is the list of fields from $SPECIAL_FIELDS that can
  2462. // be submitted as arrays of values, for example:
  2463. // <select name="recipients[]">
  2464. // <option value="sales">Sales</option>
  2465. // <option value="service">Service</option>
  2466. // </select>
  2467. //
  2468. $SPECIAL_ARRAYS = array(
  2469. "recipients",
  2470. "cc",
  2471. "bcc",
  2472. "replyto",
  2473. );
  2474. //
  2475. // $SPECIAL_NOSTRIP is the list of fields from $SPECIAL_FIELDS that
  2476. // should not be stripped (other than for magic_quotes_gpc reasons).
  2477. //
  2478. $SPECIAL_NOSTRIP = array(
  2479. "conditions",
  2480. "fmcompute",
  2481. "recaptcha_response_field",
  2482. "recaptcha_challenge_field",
  2483. );
  2484. //
  2485. // VALID_MAIL_OPTIONS lists the valid mail_options words
  2486. //
  2487. $VALID_MAIL_OPTIONS = array(
  2488. "AlwaysEmailFiles"=>true,
  2489. "AlwaysList"=>true,
  2490. "CharSet"=>true,
  2491. "DupHeader"=>true,
  2492. "Exclude"=>true,
  2493. "FromAddr"=>true,
  2494. "FromLineStyle"=>true,
  2495. "HTMLTemplate"=>true,
  2496. "KeepLines"=>true,
  2497. "NoEmpty"=>true,
  2498. "NoPlain"=>true,
  2499. "PlainTemplate"=>true,
  2500. "SendMailFOption"=>true,
  2501. "StartLine"=>true,
  2502. "TemplateMissing"=>true,
  2503. );
  2504. //
  2505. // VALID_CRM_OPTIONS lists the valid crm_options words
  2506. //
  2507. $VALID_CRM_OPTIONS = array(
  2508. "ErrorOnFail"=>true,
  2509. );
  2510. //
  2511. // VALID_AR_OPTIONS lists the valid autorespond words
  2512. //
  2513. $VALID_AR_OPTIONS = array(
  2514. "Subject"=>true,
  2515. "HTMLTemplate"=>true,
  2516. "PlainTemplate"=>true,
  2517. "TemplateMissing"=>true,
  2518. "PlainFile"=>true,
  2519. "HTMLFile"=>true,
  2520. "FromAddr"=>true,
  2521. );
  2522. //
  2523. // VALID_FILTER_OPTIONS lists the valid filter_options words
  2524. //
  2525. $VALID_FILTER_OPTIONS = array(
  2526. "Attach"=>true,
  2527. "KeepInLine"=>true,
  2528. "CSVHeading"=>true,
  2529. "CSVSep"=>true,
  2530. "CSVIntSep"=>true,
  2531. "CSVQuote"=>true,
  2532. "CSVEscPolicy"=>true,
  2533. "CSVRaw"=>true,
  2534. );
  2535. //
  2536. // SPECIAL_VALUES is set to the value of the fields we've found
  2537. // usage: $SPECIAL_VALUES["email"] is the value of the email field
  2538. //
  2539. $SPECIAL_VALUES = array();
  2540. //
  2541. // Array of mail options; set by the function 'ProcessMailOptions'
  2542. //
  2543. $MAIL_OPTS = array();
  2544. //
  2545. // Array of crm options; set by the function 'ProcessCRMOptions'
  2546. //
  2547. $CRM_OPTS = array();
  2548. //
  2549. // Array of autorespond options; set by the function 'ProcessAROptions'
  2550. //
  2551. $AR_OPTS = array();
  2552. //
  2553. // Array of filter options; set by the function 'ProcessFilterOptions'
  2554. //
  2555. $FILTER_OPTS = array();
  2556. //
  2557. // initialise $SPECIAL_VALUES so that we don't fail on using unset values
  2558. //
  2559. foreach ($SPECIAL_FIELDS as $sFieldName)
  2560. $SPECIAL_VALUES[$sFieldName] = "";
  2561. //
  2562. // Defaults for some special fields....
  2563. //
  2564. $SPECIAL_VALUES['template_list_sep'] = ",";
  2565. //
  2566. // FORMATTED_INPUT contains the input variables formatted nicely
  2567. // This is used for error reporting and debugging only.
  2568. //
  2569. $FORMATTED_INPUT = array();
  2570. //
  2571. // $FILTER_ATTRIBS_LOOKUP is the parsed $FILTER_ATTRIBS array
  2572. //
  2573. $FILTER_ATTRIBS_LOOKUP = array();
  2574. //
  2575. // $EMAIL_ADDRS is the array of email addresses from the $FORM_INI_FILE
  2576. //
  2577. $EMAIL_ADDRS = array();
  2578. $reCaptchaProcessor = null;
  2579. if ($RECAPTCHA_PRIVATE_KEY !== "")
  2580. {
  2581. require_once("recaptchalib.php");
  2582. /*
  2583. * Class: reCaptchaWrapper
  2584. * Description:
  2585. * Wraps processing of reCaptcha.
  2586. */
  2587. class reCaptchaWrapper
  2588. {
  2589. var $_sPrivate; // the private key
  2590. var $_bDone; // true when done
  2591. var $_Resp; // the response from reCaptcha
  2592. /*
  2593. * Method: reCaptchaWrapper ctor
  2594. * Parameters: $s_priv the private key
  2595. * Returns: n/a
  2596. * Description:
  2597. * Initializes the wrapper ready to process reCaptcha.
  2598. */
  2599. function reCaptchaWrapper($s_priv)
  2600. {
  2601. $this->_sPrivate = $s_priv;
  2602. $this->_bDone = false;
  2603. }
  2604. /*
  2605. * Method: reCaptchaWrapper::Check
  2606. * Parameters: $s_response the reCaptcha respone value
  2607. * $a_values field values
  2608. * $s_error returns the reCaptcha error code
  2609. * Returns: bool true on success, otherwise false
  2610. * Description:
  2611. * Performs the reCaptcha check and caches the result so it's
  2612. * only done once.
  2613. */
  2614. function Check($s_response,$a_values,&$s_error)
  2615. {
  2616. if (!$this->_bDone)
  2617. $this->_Resp = recaptcha_check_answer($this->_sPrivate,
  2618. $_SERVER["REMOTE_ADDR"],
  2619. $a_values["recaptcha_challenge_field"],
  2620. $s_response);
  2621. $this->_bDone = true;
  2622. $s_error = "";
  2623. if (!$this->_Resp->is_valid)
  2624. $s_error = $this->_Resp->error;
  2625. return ($this->_Resp->is_valid);
  2626. }
  2627. };
  2628. $reCaptchaProcessor = new reCaptchaWrapper($RECAPTCHA_PRIVATE_KEY);
  2629. }
  2630. /*
  2631. * Class: EmailChecker
  2632. * Description:
  2633. * Contains a list of valid email addresses and email address patterns.
  2634. * Provides methods for checking the validity of an email address.
  2635. */
  2636. class EmailChecker
  2637. {
  2638. var $_aAddresses; // valid email addresses (as keys)
  2639. var $_aTargetPatterns; // valid email address patterns
  2640. /*
  2641. * Method: EmailChecker ctor
  2642. * Parameters: $a_patterns an array of email address patterns
  2643. * Returns: n/a
  2644. * Description:
  2645. * Constructs the object.
  2646. */
  2647. function EmailChecker($a_patterns = array())
  2648. {
  2649. $this->_aAddresses = array();
  2650. $this->_aTargetPatterns = $a_patterns;
  2651. }
  2652. /*
  2653. * Method: EmailChecker::AddAddress
  2654. * Parameters: $s_addr an email address
  2655. * Returns: void
  2656. * Description:
  2657. * Adds an email address to the list of valid email addresses.
  2658. */
  2659. function AddAddress($s_addr)
  2660. {
  2661. $this->_aAddresses[$s_addr] = true;
  2662. }
  2663. /*
  2664. * Method: EmailChecker::AddAddresses
  2665. * Parameters: $s_list a list ofemail addresses
  2666. * Returns: void
  2667. * Description:
  2668. * Adds a comma-separated list of email addresses to the list of valid email addresses.
  2669. */
  2670. function AddAddresses($s_list)
  2671. {
  2672. $a_addrs = TrimArray(explode(",",$s_list));
  2673. foreach ($a_addrs as $s_addr)
  2674. $this->AddAddress($s_addr);
  2675. }
  2676. /*
  2677. * Method: EmailChecker::CheckAddress
  2678. * Parameters: $s_email an email address
  2679. * Returns: bool true if the address is valid, otherwise false
  2680. * Description:
  2681. * Checks an email address for validity.
  2682. */
  2683. function CheckAddress($s_email)
  2684. {
  2685. $b_is_valid = false;
  2686. if (isset($this->_aAddresses[$s_email]))
  2687. $b_is_valid = true;
  2688. else
  2689. {
  2690. for ($ii = 0 ; $ii < count($this->_aTargetPatterns) ; $ii++)
  2691. {
  2692. //
  2693. // prepend / with \
  2694. //
  2695. $s_pat = "/".str_replace('/','\\/',$this->_aTargetPatterns[$ii])."/i";
  2696. if (preg_match($s_pat,$s_email))
  2697. {
  2698. $b_is_valid = true;
  2699. break;
  2700. }
  2701. }
  2702. }
  2703. return ($b_is_valid);
  2704. }
  2705. };
  2706. //
  2707. // Create the object for checking emails
  2708. //
  2709. $ValidEmails = new EmailChecker($TARGET_EMAIL);
  2710. /*
  2711. * Class: FieldManager
  2712. * Description:
  2713. * Encapsulates storage and lookup of field data.
  2714. * NOTE: this is initial code implemented in version 8.27 and is not complete.
  2715. * It's part of our transition to a more complete Object Oriented code base
  2716. * which is targeted for version 9.00.
  2717. */
  2718. class FieldManager
  2719. {
  2720. var $_aFields; // list of fields keyed by field name
  2721. var $_aFileFields; // list of file fields keyed by field name (not currently used)
  2722. var $_sArraySep; // last array separator specified
  2723. var $_sArraySepValue; // array separator to use (after substitutions)
  2724. var $_nUnique; // counter for unique string generation
  2725. /*
  2726. * Method: FieldManager ctor
  2727. * Parameters: $a_fields list of fields
  2728. * $a_file_fields list of file fields
  2729. * Returns: n/a
  2730. * Description:
  2731. * Constructs the object.
  2732. */
  2733. function FieldManager($a_fields = array(),$a_file_fields = array())
  2734. {
  2735. $this->_sArraySepValue = $this->_sArraySep = "";
  2736. $this->_aFields = $this->_aFileFields = array();
  2737. $this->_nUnique = 0;
  2738. $this->Init($a_fields,$a_file_fields);
  2739. }
  2740. /*
  2741. * Method: FieldManager::Init
  2742. * Parameters: $a_fields list of fields
  2743. * $a_file_fields list of file fields
  2744. * Returns: void
  2745. * Description:
  2746. * Initializes the object with the field data.
  2747. */
  2748. function Init($a_fields,$a_file_fields)
  2749. {
  2750. $this->_aFields = $a_fields;
  2751. $this->_aFileFields = $a_file_fields;
  2752. }
  2753. /*
  2754. * Method: FieldManager::GetFieldValue
  2755. * Parameters: $s_fld name of the field
  2756. * $s_array_sep string to use to separate array values
  2757. * Returns: string the field's value
  2758. * Description:
  2759. * Return a field value. Empty string is returned if the field is
  2760. * not found. File fields return the original name of the uploaded file.
  2761. */
  2762. function GetFieldValue($s_fld,$s_array_sep = ";")
  2763. {
  2764. if (!isset($this->_aFields[$s_fld]))
  2765. {
  2766. if (($s_name = GetFileName($s_fld)) === false)
  2767. $s_name = "";
  2768. $s_value = $s_name;
  2769. }
  2770. if (is_array($this->_aFields[$s_fld]))
  2771. $s_value = implode($this->_GetArraySep($s_array_sep),$this->_aFields[$s_fld]);
  2772. else
  2773. $s_value = (string) $this->_aFields[$s_fld];
  2774. return ($s_value);
  2775. }
  2776. /*
  2777. * Method: FieldManager::GetSafeFieldValue
  2778. * Parameters: $s_fld name of the field
  2779. * $b_text_subs perform text substitutions
  2780. * $s_array_sep string to use to separate array values
  2781. * Returns: string the field's value
  2782. * Description:
  2783. * Return a field value. Empty string is returned if the field is
  2784. * not found. File fields return the original name of the uploaded file.
  2785. * The returned value is HTML-safe.
  2786. * b_text_subs performs text substitutions on the field value
  2787. * that are not affected by HTML-safety replacement. This means
  2788. * $TEXT_SUBS can be used to force allowance of particular HTML
  2789. * tags. Note that b_text_subs is not yet implemented for array field
  2790. * values.
  2791. */
  2792. function GetSafeFieldValue($s_fld,$b_text_subs = false,$s_array_sep = ";")
  2793. {
  2794. //
  2795. // for array values, insert the array separator after making
  2796. // the individual values HTML-safe
  2797. // The equivalent logic up to and including version 8.24 used
  2798. // htmlspecialchars not htmlentities.
  2799. // The use of htmlentities broke UTF-8 template processing,
  2800. // and this was reported in version 8.28.
  2801. // By specifying the character set, we trigger the use of htmlspecialchars
  2802. // so the logic is equivalent to the old logic.
  2803. //
  2804. if (isset($this->_aFields[$s_fld]) && is_array($this->_aFields[$s_fld]))
  2805. $s_value = implode($this->_GetArraySep($s_array_sep),
  2806. HTMLEntitiesArray($this->_aFields[$s_fld],false,
  2807. GetMailOption("CharSet")));
  2808. else
  2809. {
  2810. if (!isset($this->_aFields[$s_fld]))
  2811. {
  2812. if (($s_name = GetFileName($s_fld)) === false)
  2813. $s_name = "";
  2814. $s_value = $s_name;
  2815. }
  2816. else
  2817. $s_value = (string) $this->_aFields[$s_fld];
  2818. if ($b_text_subs)
  2819. list($s_value,$a_subs_data) = $this->_PrepareTextSubstitute($s_value);
  2820. $s_value = FixedHTMLEntities($s_value,GetMailOption("CharSet"));
  2821. if ($b_text_subs)
  2822. $s_value = $this->_CompleteTextSubstitute($s_value,$a_subs_data);
  2823. }
  2824. return ($s_value);
  2825. }
  2826. /*
  2827. * Method: FieldManager::_PrepareTextSubstitute
  2828. * Parameters: $s_value the value to perform substitutions on
  2829. * Returns: array [0]=>the processed value, [1]=>array of substitution data
  2830. * Description:
  2831. * Prepares a value for text substitution using $TEXT_SUBS.
  2832. * Requires PHP 4.3.0 or later.
  2833. */
  2834. function _PrepareTextSubstitute($s_value)
  2835. {
  2836. global $TEXT_SUBS;
  2837. $a_subs_data = array();
  2838. if (!IsPHPAtLeast("4.3.0"))
  2839. SendAlert("The text substitution feature requires PHP version 4.3.0 or later");
  2840. else
  2841. {
  2842. for ($ii = 0; $ii < count($TEXT_SUBS); $ii++)
  2843. {
  2844. $a_match_data = array();
  2845. if (($n_matches = preg_match_all($TEXT_SUBS[$ii]["srch"],
  2846. $s_value,$a_matches,
  2847. PREG_OFFSET_CAPTURE)) !== false && $n_matches > 0)
  2848. {
  2849. $a_match_data["srch"] = $TEXT_SUBS[$ii]["srch"];
  2850. $a_match_data["repl"] = $TEXT_SUBS[$ii]["repl"];
  2851. $s_value = $this->_HTMLSafeSubstitute($s_value,$a_matches,$a_match_data);
  2852. }
  2853. $a_subs_data[$ii] = $a_match_data;
  2854. }
  2855. }
  2856. return (array($s_value,$a_subs_data));
  2857. }
  2858. /*
  2859. * Method: FieldManager::_CompleteTextSubstitute
  2860. * Parameters: $s_value the value to perform substitutions on
  2861. * $a_subs_data data that describes the substitutions to perform
  2862. * Returns: string the new value
  2863. * Description:
  2864. * Completes text substitution started by _PrepareTextSubstitute.
  2865. */
  2866. function _CompleteTextSubstitute($s_value,$a_subs_data)
  2867. {
  2868. //
  2869. // because later substitutions can capture earlier ones,
  2870. // we have to process them all in reverse order
  2871. //
  2872. for ($ii = count($a_subs_data) ; --$ii >= 0 ; )
  2873. {
  2874. $a_subs_list = $a_subs_data[$ii];
  2875. for ($jj = count($a_subs_list) ; --$jj >= 0 ; )
  2876. {
  2877. $s_code = $a_subs_list[$jj]["code"];
  2878. $s_subs = $a_subs_list[$jj]["subs"];
  2879. $s_value = str_replace($s_code,$s_subs,$s_value);
  2880. }
  2881. }
  2882. return ($s_value);
  2883. }
  2884. /*
  2885. * Method: FieldManager::_MakeUniqueString
  2886. * Parameters: $s_base a base of the unique string
  2887. * Returns: string a unique string
  2888. * Description:
  2889. * Generates a unique string from a base string
  2890. */
  2891. function _MakeUniqueString($s_base)
  2892. {
  2893. $n_uniq = $this->_nUnique++;
  2894. return ($s_base."_".str_pad("$n_uniq",5,"0",STR_PAD_LEFT));
  2895. }
  2896. /*
  2897. * Method: FieldManager::_HTMLSafeSubstitute
  2898. * Parameters: $s_value the string to substitute
  2899. * $a_matches list of matches and offsets from preg_match_all
  2900. * $a_match_data contains some data, and returns replacement data
  2901. * for the temporary substitution
  2902. * Returns: string the temporarily substituted string
  2903. * Description:
  2904. * Performs a temporary substitution on a string of the given matches with
  2905. * the given replacement specification. This makes the replacement using
  2906. * a special indicator string that can be substituted for the real value
  2907. * later. This allows non-replaced parts of the string to be processed
  2908. * and made safe for HTML entities, without affecting our actual replacements.
  2909. */
  2910. function _HTMLSafeSubstitute($s_value,$a_matches,&$a_match_data)
  2911. {
  2912. $a_matches = $a_matches[0]; // we're only interested in the full pattern matches
  2913. $s_srch = $a_match_data["srch"];
  2914. $s_repl = $a_match_data["repl"];
  2915. //
  2916. // to preserve offsets, we must process the string in reverse order
  2917. // of the matches; since we don't assume the array is ordered
  2918. // by ascending offset, we'll sort it now
  2919. //
  2920. usort($a_matches,create_function('$a,$b','return $b[1] - $a[1];'));
  2921. $a_match_data = array();
  2922. for ($ii = 0; $ii < count($a_matches); $ii++)
  2923. {
  2924. $s_match = $a_matches[$ii][0];
  2925. $i_offset = $a_matches[$ii][1];
  2926. $i_len = strlen($s_match);
  2927. $s_subs = preg_replace($s_srch,$s_repl,$s_match);
  2928. //
  2929. // the code string must e HTML safe so it doesn't get altered
  2930. // before we can replace it; we use ! at the edges so that
  2931. // other patterns can successfully match word boundaries
  2932. // An improvement would be to determine the type of characters
  2933. // at the edges of the matched string, then choose the substitution
  2934. // edges accordingly.
  2935. //
  2936. $s_code = "!".$this->_MakeUniqueString("SUBS")."!";
  2937. $a_match_data[$ii] = array("subs"=>$s_subs,"code"=>$s_code);
  2938. $s_value = substr($s_value,0,$i_offset).$s_code.
  2939. substr($s_value,$i_offset + $i_len);
  2940. }
  2941. return ($s_value);
  2942. }
  2943. /*
  2944. * Method: FieldManager::IsFieldSet
  2945. * Parameters: $s_fld name of the field
  2946. * Returns: bool true if the field has a value
  2947. * Description:
  2948. * Test if a field is set in the $_aFields array or in the uploaded
  2949. * files.
  2950. */
  2951. /*static*/ function IsFieldSet($s_fld)
  2952. {
  2953. global $aFileVars; // temporary code until this class is complete
  2954. if (isset($this->_aFields[$s_fld]))
  2955. return (true);
  2956. if (FILEUPLOADS)
  2957. {
  2958. if (isset($aFileVars[$s_fld]))
  2959. return (true);
  2960. if (IsSetSession("FormSavedFiles"))
  2961. {
  2962. $a_saved_files = GetSession("FormSavedFiles");
  2963. if (isset($a_saved_files[$s_fld]))
  2964. return (true);
  2965. }
  2966. }
  2967. return (false);
  2968. }
  2969. /*
  2970. * Method: FieldManager::TestFieldEmpty
  2971. * Parameters: $s_fld name of the field
  2972. * $s_mesg returns an error message, where possible
  2973. * Returns: bool true if the field is empty
  2974. * Description:
  2975. * Tests a field against the $_aFields array for emptyness.
  2976. * If the var isn't found there, then the POSTed files array is checked.
  2977. * Returns true if the field is empty (a specific error may
  2978. * be returned in the $s_mesg parameter).
  2979. */
  2980. /*static*/ function TestFieldEmpty($s_fld,&$s_mesg)
  2981. {
  2982. global $aFileVars; // temporary until code completed
  2983. $s_mesg = "";
  2984. $b_empty = TRUE;
  2985. if (!isset($this->_aFields[$s_fld]))
  2986. {
  2987. //
  2988. // Each file var is an array with these elements:
  2989. // "name" => The original name of the file on the client machine.
  2990. // "type" => The mime type of the file, if the browser provided this information.
  2991. // "tmp_name" => The temporary filename of the file in which the uploaded file was stored on the server.
  2992. // "error" => The error code associated with this file upload.
  2993. // NOTE: "error" was added in PHP 4.2.0
  2994. // "size" => The size, in bytes, of the uploaded file.
  2995. //
  2996. // Error codes (the constants are only available from PHP 4.3.0 so
  2997. // we have to use the raw numbers):
  2998. // UPLOAD_ERR_OK
  2999. // Value: 0; There is no error, the file uploaded with success.
  3000. // UPLOAD_ERR_INI_SIZE
  3001. // Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
  3002. // UPLOAD_ERR_FORM_SIZE
  3003. // Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.
  3004. // UPLOAD_ERR_PARTIAL
  3005. // Value: 3; The uploaded file was only partially uploaded.
  3006. // UPLOAD_ERR_NO_FILE
  3007. // Value: 4; No file was uploaded.
  3008. //
  3009. if (FILEUPLOADS)
  3010. {
  3011. if (IsSetSession("FormSavedFiles"))
  3012. {
  3013. $a_saved_files = GetSession("FormSavedFiles");
  3014. if (isset($a_saved_files[$s_fld]))
  3015. $a_upload = $a_saved_files[$s_fld];
  3016. elseif (isset($aFileVars[$s_fld]))
  3017. $a_upload = $aFileVars[$s_fld];
  3018. }
  3019. elseif (isset($aFileVars[$s_fld]))
  3020. $a_upload = $aFileVars[$s_fld];
  3021. }
  3022. if (isset($a_upload))
  3023. {
  3024. if (isset($a_upload["tmp_name"]) && !empty($a_upload["tmp_name"]) &&
  3025. isset($a_upload["name"]) && !empty($a_upload["name"]))
  3026. {
  3027. if (IsUploadedFile($a_upload))
  3028. $b_empty = false;
  3029. }
  3030. if ($b_empty && isset($a_upload["error"]))
  3031. switch ($a_upload["error"])
  3032. {
  3033. case 1:
  3034. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR1);
  3035. break;
  3036. case 2:
  3037. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR2);
  3038. break;
  3039. case 3:
  3040. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR3);
  3041. break;
  3042. case 4:
  3043. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR4);
  3044. break;
  3045. case 6:
  3046. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR6);
  3047. break;
  3048. case 7:
  3049. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR7);
  3050. break;
  3051. case 8:
  3052. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR8);
  3053. break;
  3054. default:
  3055. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR_UNK,
  3056. array("ERRNO"=>$a_upload["error"]));
  3057. break;
  3058. }
  3059. }
  3060. }
  3061. else
  3062. $b_empty = FieldManager::IsEmpty($this->_aFields[$s_fld]);
  3063. return ($b_empty);
  3064. }
  3065. /*
  3066. * Method: FieldManager::IsEmpty
  3067. * Parameters: $s_value the value to test
  3068. * Returns: bool true if the value is "empty"
  3069. * Description:
  3070. * Same as "empty" but checks for true emptiness if ZERO_IS_EMPTY is
  3071. * set to false.
  3072. */
  3073. /*static*/ function IsEmpty($s_value)
  3074. {
  3075. if (ZERO_IS_EMPTY || is_array($s_value))
  3076. return (empty($s_value));
  3077. else
  3078. return ($s_value === "");
  3079. }
  3080. /*
  3081. * Method: FieldManager::Substitute
  3082. * Parameters: $s_str a string on which to perform substitutions
  3083. * Returns: string the string, substituted
  3084. * Description:
  3085. * Makes substitutions on strings as specified in the configuration setting
  3086. * $TEXT_SUBS.
  3087. */
  3088. /*static*/ function Substitute($s_str)
  3089. {
  3090. global $TEXT_SUBS;
  3091. $a_srch = $a_repl = array();
  3092. foreach ($TEXT_SUBS as $a_sub)
  3093. {
  3094. if (isset($a_sub["srch"]) &&
  3095. isset($a_sub["repl"]) &&
  3096. $a_sub["srch"] !== "")
  3097. {
  3098. $a_srch[] = $a_sub["srch"];
  3099. $a_repl[] = $a_sub["repl"];
  3100. }
  3101. }
  3102. return (preg_replace($a_srch,$a_repl,$s_str));
  3103. }
  3104. /*
  3105. * Method: FieldManager::_GetArraySep
  3106. * Parameters: $s_sep the string specified for array separations
  3107. * Returns: string the string to use for array separations
  3108. * Description:
  3109. * Computes the array separation string. $s_sep is subject to
  3110. * subsititions specified in $TEXT_SUBS, and then returned.
  3111. */
  3112. function _GetArraySep($s_sep)
  3113. {
  3114. //
  3115. // check for cached (previously calculated) value
  3116. //
  3117. if ($s_sep !== $this->_sArraySep)
  3118. {
  3119. $this->_sArraySep = $s_sep;
  3120. $this->_sArraySepValue = FieldManager::Substitute($this->_sArraySep);
  3121. }
  3122. return ($this->_sArraySepValue);
  3123. }
  3124. }
  3125. //
  3126. // Peform general line folding.
  3127. // This function can be used for RFC 2822 line folding, as well
  3128. // Quoted Printable soft line breaks (RFC 2045).
  3129. // $s_before lists the characters before which we should fold the line.
  3130. // $s_after lists the characters after which we should fold the line.
  3131. // $s_fold is the string to insert to fold the line.
  3132. //
  3133. function LineFolding($s_str,$i_max_line,$s_before,$s_after,$s_fold)
  3134. {
  3135. $i_str_len = strlen($s_str);
  3136. $ii = $i_start = 0;
  3137. $i_line_len = 0;
  3138. while ($ii < $i_str_len)
  3139. {
  3140. if ($i_line_len == $i_max_line)
  3141. {
  3142. //
  3143. // fold this line:
  3144. // search backwards for a character at which we can
  3145. // fold the line
  3146. //
  3147. $b_done = false;
  3148. for ($jj = $ii ; !$b_done && $jj > $i_start ; $jj--)
  3149. {
  3150. $b_found = false;
  3151. if (strpos($s_before,$s_str[$jj]) !== false)
  3152. {
  3153. //
  3154. // fold before this character
  3155. //
  3156. $b_found = true;
  3157. }
  3158. elseif (strpos($s_after,$s_str[$jj]) !== false)
  3159. {
  3160. //
  3161. // fold after this character
  3162. //
  3163. $jj++;
  3164. $b_found = true;
  3165. }
  3166. if ($b_found)
  3167. {
  3168. $s_str = substr($s_str,0,$jj).$s_fold.substr($s_str,$jj);
  3169. $i_fold_len = strlen($s_fold);
  3170. $i_str_len += $i_fold_len; // the additional chars we inserted
  3171. $i_start = $jj + $i_fold_len; // start of the next line
  3172. $b_done = true;
  3173. }
  3174. }
  3175. //
  3176. // if we cannot fold and shorten the line,
  3177. // ignore this and try for the next line
  3178. //
  3179. if ($b_done)
  3180. $ii = $i_start;
  3181. else
  3182. $i_start = $ii;
  3183. $i_line_len = 0;
  3184. }
  3185. elseif (substr($s_str,$ii,2) == "\r\n")
  3186. {
  3187. //
  3188. // end of line found - reset counters
  3189. //
  3190. $i_line_len = 0;
  3191. $ii += 2;
  3192. $i_start = $ii;
  3193. }
  3194. else
  3195. {
  3196. $ii++;
  3197. $i_line_len++;
  3198. }
  3199. }
  3200. return ($s_str);
  3201. }
  3202. //
  3203. // Quoted Printable Encoding with soft line breaks.
  3204. //
  3205. // Process a string to fit the requirements of RFC2045 section 6.7. Note that
  3206. // this works, but replaces more characters than the minimum set.
  3207. // Prior to version 8.34, for readability the spaces were not encoded, which was
  3208. // WRONG (see http://tools.ietf.org/html/rfc2047#section-2). Spaces must
  3209. // be encoded.
  3210. //
  3211. // Adapted from:
  3212. // http://www.php.net/manual/en/function.quoted-printable-decode.php
  3213. // Note that we *must* split long lines because a QP string might not
  3214. // contain any Folding White Space (FWS). In this case, it would
  3215. // not be possible to fold the line according to RFC 2822.
  3216. // Therefore, we need to use Soft Line Breaks as defined by the
  3217. // Quoted Printable definition in RFC 2045.
  3218. //
  3219. // Set $i_max_line to -ve to skip the line folding.
  3220. //
  3221. function QPEncode($s_str,$i_max_line)
  3222. {
  3223. //
  3224. // According to RFC2045 section 6.7 point (4), we need to keep any
  3225. // actual \r\n breaks encoded in the QP. The original code replaced
  3226. // them with CRLF pairs.
  3227. //
  3228. $s_str = str_replace('%','=',rawurlencode($s_str));
  3229. if ($i_max_line < 0)
  3230. return ($s_str);
  3231. else
  3232. {
  3233. $s_before = "="; // characters before which we can fold the line
  3234. return (LineFolding($s_str,$i_max_line,$s_before,"","=\r\n"));
  3235. }
  3236. }
  3237. //
  3238. // Peform header line folding according to RFC 2822.
  3239. // $s_before lists the characters before which we should fold the line.
  3240. // $s_after lists the characters after which we should fold the line.
  3241. // Characters left out of folding:
  3242. // [] are part of no-fold-literal
  3243. // () are part of comments, and should work, but don't
  3244. //
  3245. function HeaderFolding($s_str,$i_max_line = RFCLINELEN,$s_before = "<",$s_after = ">;, ")
  3246. {
  3247. return (LineFolding($s_str,$i_max_line,$s_before,$s_after,"\r\n "));
  3248. }
  3249. //
  3250. // Access the www.tectite.com website to get the current version.
  3251. //
  3252. function CheckVersion()
  3253. {
  3254. global $FM_VERS;
  3255. $http_get = new HTTPGet("http://www.tectite.com/fmversion.txt");
  3256. $php_errormsg = ""; // clear this out in case we get an error that doesn't set it
  3257. FMDebug("CheckVersion");
  3258. if (($a_lines = $http_get->Read()) !== false)
  3259. {
  3260. //
  3261. // version file looks like this:
  3262. // Version=versionumber
  3263. // Message=a message to send in the alert
  3264. //
  3265. $s_version = "";
  3266. $s_message = "";
  3267. $s_line = "";
  3268. $b_in_mesg = false;
  3269. foreach ($a_lines as $s_line)
  3270. {
  3271. if ($b_in_mesg)
  3272. $s_message .= $s_line;
  3273. else
  3274. {
  3275. $s_prefix = substr($s_line,0,8);
  3276. if ($s_prefix == "Message=")
  3277. {
  3278. $s_message .= substr($s_line,8);
  3279. $b_in_mesg = true;
  3280. }
  3281. elseif ($s_prefix == "Version=")
  3282. $s_version = substr($s_line,8);
  3283. }
  3284. }
  3285. $s_version = str_replace("\r","",$s_version);
  3286. $s_version = str_replace("\n","",$s_version);
  3287. $s_stop_mesg = GetMessage(MSG_END_VERS_CHK);
  3288. FMDebug("CheckVersion: vers=$s_version");
  3289. if ((float) $s_version > (float) $FM_VERS)
  3290. SendAlert(GetMessage(MSG_VERS_CHK,array(
  3291. "TECTITE"=>"www.tectite.com",
  3292. "FM_VERS"=>"$FM_VERS",
  3293. "NEWVERS"=>$s_version,
  3294. ))."\n$s_message\n$s_stop_mesg",true,true);
  3295. }
  3296. }
  3297. //
  3298. // Check for new FormMail version
  3299. //
  3300. function Check4Update($s_chk_file,$s_id = "")
  3301. {
  3302. global $lNow,$php_errormsg;
  3303. @ $l_last_chk = filemtime($s_chk_file);
  3304. if ($l_last_chk === false || $lNow - $l_last_chk >= (CHECK_DAYS*24*60*60))
  3305. {
  3306. CheckVersion();
  3307. //
  3308. // update the check file's time stamp
  3309. //
  3310. @ $fp = fopen($s_chk_file,"w");
  3311. if ($fp !== false)
  3312. {
  3313. fwrite($fp,"FormMail version check ".
  3314. (empty($s_id) ? "" : "for identifier '$s_id' ").
  3315. "at ".date("H:i:s d-M-Y",$lNow)."\n");
  3316. fclose($fp);
  3317. }
  3318. else
  3319. SendAlert(GetMessage(MSG_CHK_FILE_ERROR,array("FILE"=>$s_chk_file,
  3320. "ERROR"=>CheckString($php_errormsg))));
  3321. }
  3322. }
  3323. //
  3324. // Perform various processing at the end of the script's execution.
  3325. //
  3326. function OnExit()
  3327. {
  3328. global $TARGET_EMAIL,$CHECK_FILE;
  3329. FMDebug("OnExit");
  3330. //
  3331. // Check the www.tectite.com website for a new version, but only
  3332. // do this check once every CHECK_DAYS days (or on server reboot).
  3333. //
  3334. if (CHECK_FOR_NEW_VERSION)
  3335. {
  3336. global $SERVER;
  3337. if (isset($TARGET_EMAIL[0]))
  3338. {
  3339. //
  3340. // use the first few characters of the MD5 of first email
  3341. // address pattern from $TARGET_EMAIL to get a unique file
  3342. // for the server
  3343. //
  3344. $s_id = "";
  3345. if (isset($SERVER) && !empty($SERVER))
  3346. $s_id = $SERVER;
  3347. $s_dir = GetTempDir();
  3348. $s_md5 = md5($TARGET_EMAIL[0]);
  3349. $s_uniq = substr($s_md5,0,6);
  3350. $s_chk_file = "fm"."$s_uniq".".txt";
  3351. Check4Update($s_dir."/".$s_chk_file,$s_id);
  3352. }
  3353. }
  3354. }
  3355. register_shutdown_function('OnExit');
  3356. //
  3357. // Return the array with each string processed by htmlentities
  3358. //
  3359. function HTMLEntitiesArray($a_array,$b_equals_processing = false,$s_charset = NULL)
  3360. {
  3361. foreach ($a_array as $m_key=>$s_str)
  3362. {
  3363. //
  3364. // only encode the value after the '='
  3365. //
  3366. if ($b_equals_processing && ($i_pos = strpos($s_str,'=')) !== false)
  3367. $a_array[$m_key] = substr($s_str,0,$i_pos+1).
  3368. FixedHTMLEntities(substr($s_str,$i_pos+1),$s_charset);
  3369. else
  3370. $a_array[$m_key] = FixedHTMLEntities($s_str,$s_charset);
  3371. }
  3372. return ($a_array);
  3373. }
  3374. //
  3375. // Unfortunately, htmlentities (in some versions of PHP) gets
  3376. // some characters wrong and converts them even when the
  3377. // charset is provided.
  3378. // This function overcomes this problem.
  3379. //
  3380. function FixedHTMLEntities($s_str,$s_charset = NULL)
  3381. {
  3382. global $sHTMLCharSet;
  3383. if (isset($s_charset) && $s_charset != "")
  3384. return (htmlspecialchars($s_str,ENT_COMPAT,$s_charset));
  3385. if (isset($sHTMLCharSet) && $sHTMLCharSet != "")
  3386. return (htmlspecialchars($s_str,ENT_COMPAT,$sHTMLCharSet));
  3387. return (htmlentities($s_str));
  3388. }
  3389. //
  3390. // Return the array with each string urlencode'd.
  3391. //
  3392. function URLEncodeArray($a_array)
  3393. {
  3394. foreach ($a_array as $m_key=>$s_str)
  3395. {
  3396. //
  3397. // only encode the value after the '='
  3398. //
  3399. if (($i_pos = strpos($s_str,'=')) !== false)
  3400. $a_array[$m_key] = substr($s_str,0,$i_pos+1).
  3401. urlencode(substr($s_str,$i_pos+1));
  3402. else
  3403. $a_array[$m_key] = urlencode($s_str);
  3404. }
  3405. return ($a_array);
  3406. }
  3407. //
  3408. // Performs charset encoding for header line text.
  3409. // This operates according to RFC 2047, but without
  3410. // imposing the 75 character limit on an encoding.
  3411. // I haven't implemented that because of all the dramas
  3412. // with *trying* to obey the header line length rules that
  3413. // don't seem to work with PHP, the MTA, and email clients.
  3414. //
  3415. function EncodeHeaderText($s_text,$i_max_line = -1)
  3416. {
  3417. global $sHTMLCharSet;
  3418. //
  3419. // RFCLINELEN is the RFC recommended maximum line length, but we don't know
  3420. // what the front part of the line will be at this point.
  3421. // So, we'll be conservative and reduce it.
  3422. //
  3423. if ($i_max_line == 0)
  3424. $i_max_line = RFCLINELEN - 15;
  3425. $s_charset = "";
  3426. if (isset($sHTMLCharSet) && $sHTMLCharSet != "")
  3427. $s_charset = $sHTMLCharSet;
  3428. else if (IsMailOptionSet("CharSet"))
  3429. $s_charset = GetMailOption("CharSet");
  3430. if ($s_charset != "")
  3431. {
  3432. //
  3433. // this is the for base64 encoding.
  3434. // quoted printable is a better choice for human readability
  3435. //
  3436. //return ("=?".$s_charset."?B?".base64_encode($s_text)."?=");
  3437. $s_prefix = "=?".$s_charset."?Q?";
  3438. $s_suffix = "?=";
  3439. //
  3440. // pick a line length that allows a line split with the prefix or suffix added
  3441. // to be within the RFC maximum recommended line length
  3442. //
  3443. return ($s_prefix.QPEncode($s_text,$i_max_line-strlen($s_prefix)).$s_suffix);
  3444. }
  3445. else
  3446. return ($s_text);
  3447. }
  3448. //
  3449. // Add a parameter or list of parameters to a URL.
  3450. //
  3451. function AddURLParams($s_url,$m_params,$b_encode = true)
  3452. {
  3453. if (!empty($m_params))
  3454. {
  3455. if (!is_array($m_params))
  3456. $m_params = array($m_params);
  3457. $s_anchor = "";
  3458. if (($i_pos = strpos($s_url,'#')) !== false)
  3459. {
  3460. //
  3461. // extract the anchor
  3462. //
  3463. $s_anchor = substr($s_url,$i_pos);
  3464. $s_url = substr($s_url,0,$i_pos);
  3465. }
  3466. if (strpos($s_url,'?') === false)
  3467. $s_url .= '?';
  3468. else
  3469. $s_url .= '&';
  3470. $s_url .= implode('&',($b_encode) ? URLEncodeArray($m_params) : $m_params);
  3471. if ($s_anchor !== "")
  3472. $s_url .= "$s_anchor";
  3473. }
  3474. return ($s_url);
  3475. }
  3476. //
  3477. // Recursively trim an array of strings (non string values are converted
  3478. // to a string first).
  3479. //
  3480. function TrimArray($a_list)
  3481. {
  3482. foreach ($a_list as $m_key=>$m_item)
  3483. if (is_array($m_item))
  3484. $a_list[$m_key] = TrimArray($m_item);
  3485. elseif (is_scalar($m_item))
  3486. $a_list[$m_key] = trim("$m_item");
  3487. else
  3488. $a_list[$m_key] = "";
  3489. return ($a_list);
  3490. }
  3491. //
  3492. // Parse a derivation specification and return an array of
  3493. // field names and operators.
  3494. //
  3495. function ParseDerivation($a_form_data,$s_fld_spec,$s_name,&$a_errors)
  3496. {
  3497. $a_deriv = array();
  3498. while (($i_len = strlen($s_fld_spec)) > 0)
  3499. {
  3500. //
  3501. // we support the following operators:
  3502. // + concatenate with a single space between, but skip the space
  3503. // if the next field is empty
  3504. // * concatenate with a single space between
  3505. // . concatenate with no space between
  3506. //
  3507. $i_span = strcspn($s_fld_spec,'+*.');
  3508. if ($i_span == 0)
  3509. {
  3510. $a_errors[] = $s_name;
  3511. return (false);
  3512. }
  3513. $a_deriv[] = trim(substr($s_fld_spec,0,$i_span));
  3514. if ($i_span < $i_len)
  3515. {
  3516. $a_deriv[] = substr($s_fld_spec,$i_span,1);
  3517. $s_fld_spec = substr($s_fld_spec,$i_span+1);
  3518. }
  3519. else
  3520. $s_fld_spec = "";
  3521. }
  3522. return ($a_deriv);
  3523. }
  3524. //
  3525. // Test if a character is an alphabetic.
  3526. //
  3527. function IsAlpha($ch)
  3528. {
  3529. return (strpos("abcdefghijklmnopqrstuvwxyz",strtolower($ch)) !== false);
  3530. }
  3531. //
  3532. // Test if a character is a digit.
  3533. //
  3534. function IsNumeric($ch)
  3535. {
  3536. return (strpos("0123456789",$ch) !== false);
  3537. }
  3538. //
  3539. // Test if a character is an alphanumeric
  3540. //
  3541. function IsAlnum($ch)
  3542. {
  3543. return (IsAlpha($ch) || IsNumeric($ch));
  3544. }
  3545. //
  3546. // Return an array of tokens extracted from the given string.
  3547. // A token is:
  3548. // - a word (begins with alpha or _, and is followed by any number
  3549. // of alphanumerics or _ chars)
  3550. // - a number (any number of consecutive digits with up to one period)
  3551. // - a string enclosed in specified quotes (this can be disabled)
  3552. // - any punctuation character
  3553. //
  3554. // Anything not matching the above is silently ignored!
  3555. //
  3556. function GetTokens($s_str,$s_quotes = "'\"")
  3557. {
  3558. $b_allow_strings = ($s_quotes !== "") ? true : false;
  3559. $ii = 0;
  3560. $i_len = strlen($s_str);
  3561. $a_toks = array();
  3562. while ($ii < $i_len)
  3563. {
  3564. switch ($ch = $s_str[$ii])
  3565. {
  3566. case " ":
  3567. case "\t":
  3568. case "\n":
  3569. case "\r":
  3570. $ii++;
  3571. continue;
  3572. }
  3573. //
  3574. // start of a token
  3575. //
  3576. $i_start = $ii;
  3577. if ($ch == "_" || IsAlpha($ch))
  3578. {
  3579. //
  3580. // a word
  3581. //
  3582. $i_count = 1;
  3583. while (++$ii < $i_len &&
  3584. ($s_str[$ii] == "_" || IsAlnum($s_str[$ii])))
  3585. ++$i_count;
  3586. $a_toks[] = substr($s_str,$i_start,$i_count);
  3587. }
  3588. elseif (($ch == "." && $ii < ($i_len-1) && IsNumeric($s_str[$ii+1]))||
  3589. IsNumeric($ch))
  3590. {
  3591. //
  3592. // a number
  3593. //
  3594. $b_had_dot = ($ch == ".");
  3595. $i_count = 1;
  3596. while (++$ii < $i_len)
  3597. {
  3598. if (IsNumeric($s_str[$ii]))
  3599. ++$i_count;
  3600. elseif ($s_str[$ii] == "." && !$b_had_dot)
  3601. {
  3602. ++$i_count;
  3603. $b_had_dot = true;
  3604. }
  3605. else
  3606. break;
  3607. }
  3608. $a_toks[] = substr($s_str,$i_start,$i_count);
  3609. }
  3610. elseif ($b_allow_strings && strpos($s_quotes,$ch) !== false)
  3611. {
  3612. $c_quote = $ch;
  3613. //
  3614. // a quoted string
  3615. //
  3616. while (++$ii < $i_len)
  3617. {
  3618. if ($s_str[$ii] == $c_quote)
  3619. {
  3620. ++$ii; // include the terminating quote
  3621. break;
  3622. }
  3623. }
  3624. $a_toks[] = substr($s_str,$i_start,$ii-$i_start);
  3625. }
  3626. else
  3627. {
  3628. $s_punct = "~!@#$%^&*()-+={}[]|:;<>,.?/`\\";
  3629. if (!$b_allow_strings)
  3630. $s_punct .= "'\"";
  3631. if (strpos($s_punct,$ch) !== false)
  3632. $a_toks[] = $ch;
  3633. ++$ii;
  3634. }
  3635. }
  3636. return ($a_toks);
  3637. }
  3638. //
  3639. // Return the value from a derive_fields specification.
  3640. // Specifications are in this format:
  3641. // %info%
  3642. // where info is a predefined word or a literal in quotes
  3643. // (e.g. 'the time is ')
  3644. //
  3645. function ValueSpec($s_spec,$a_form_data,&$a_errors)
  3646. {
  3647. global $lNow;
  3648. $s_value = "";
  3649. switch (trim($s_spec))
  3650. {
  3651. case 'date': // "standard" date format: DD-MMM-YYYY
  3652. $s_value = date('d-M-Y',$lNow);
  3653. break;
  3654. case 'time': // "standard" time format: HH:MM:SS
  3655. $s_value = date('H:i:s',$lNow);
  3656. break;
  3657. case 'ampm': // am or pm
  3658. $s_value = date('a',$lNow);
  3659. break;
  3660. case 'AMPM': // AM or PM
  3661. $s_value = date('A',$lNow);
  3662. break;
  3663. case 'dom0': // day of month with possible leading zero
  3664. $s_value = date('d',$lNow);
  3665. break;
  3666. case 'dom': // day of month with no leading zero
  3667. $s_value = date('j',$lNow);
  3668. break;
  3669. case 'day': // day name (abbreviated)
  3670. $s_value = date('D',$lNow);
  3671. break;
  3672. case 'dayname': // day name (full)
  3673. $s_value = date('l',$lNow);
  3674. break;
  3675. case 'daysuffix': // day number suffix for English (st for 1st, nd for 2nd, etc.)
  3676. $s_value = date('S',$lNow);
  3677. break;
  3678. case 'moy0': // month of year with possible leading zero
  3679. $s_value = date('m',$lNow);
  3680. break;
  3681. case 'moy': // month of year with no leading zero
  3682. $s_value = date('n',$lNow);
  3683. break;
  3684. case 'month': // month name (abbreviated)
  3685. $s_value = date('M',$lNow);
  3686. break;
  3687. case 'monthname': // month name (full)
  3688. $s_value = date('F',$lNow);
  3689. break;
  3690. case 'year': // year (two digits)
  3691. $s_value = date('y',$lNow);
  3692. break;
  3693. case 'fullyear': // year (full)
  3694. $s_value = date('Y',$lNow);
  3695. break;
  3696. case 'rfcdate': // date formatted according to RFC 822
  3697. $s_value = date('r',$lNow);
  3698. break;
  3699. case 'tzname': // timezone name
  3700. $s_value = date('T',$lNow);
  3701. break;
  3702. case 'tz': // timezone difference from Greenwich +NNNN or -NNNN
  3703. $s_value = date('O',$lNow);
  3704. break;
  3705. case 'hour120': // hour of day (01-12) with possible leading zero
  3706. $s_value = date('h',$lNow);
  3707. break;
  3708. case 'hour240': // hour of day (00-23) with possible leading zero
  3709. $s_value = date('H',$lNow);
  3710. break;
  3711. case 'hour12': // hour of day (1-12) with no leading zero
  3712. $s_value = date('g',$lNow);
  3713. break;
  3714. case 'hour24': // hour of day (0-23) with no leading zero
  3715. $s_value = date('G',$lNow);
  3716. break;
  3717. case 'min': // minute of hour (00-59)
  3718. $s_value = date('i',$lNow);
  3719. break;
  3720. case 'sec': // seconds of minute (00-59)
  3721. $s_value = date('s',$lNow);
  3722. break;
  3723. default:
  3724. if ($s_spec[0] == "'")
  3725. {
  3726. //
  3727. // to get a quote, use 3 quotes:
  3728. // '''
  3729. //
  3730. if ($s_spec == "'''")
  3731. $s_value = "'";
  3732. elseif (substr($s_spec,-1,1) == "'")
  3733. $s_value = substr($s_spec,1,-1);
  3734. else
  3735. //
  3736. // missing final quote is OK
  3737. //
  3738. $s_value = substr($s_spec,1);
  3739. }
  3740. elseif (strspn($s_spec,"0123456789ABCDEF") == 2)
  3741. {
  3742. //
  3743. // insert the ASCII character corresponding to
  3744. // the hexadecimal value
  3745. //
  3746. $i_val = intval(substr($s_spec,0,2),16);
  3747. $s_value = chr($i_val);
  3748. }
  3749. else
  3750. {
  3751. //
  3752. // look for supported functions, start by getting all
  3753. // the tokens
  3754. //
  3755. $a_toks = GetTokens($s_spec);
  3756. if (count($a_toks) > 0)
  3757. {
  3758. switch ($a_toks[0])
  3759. {
  3760. case "if":
  3761. //
  3762. // "if" function: test first field
  3763. // if not empty, then use second field
  3764. // else, use third field
  3765. //
  3766. // Example: if(fld1 ; fld2 ; fld3)
  3767. //
  3768. // tokens are:
  3769. // 1 (
  3770. // 2 the field name to test (first)
  3771. // 3 ;
  3772. // 4 the "then" spec (can be missing)
  3773. // 5 ;
  3774. // 6 the "else" spec (can be missing)
  3775. // 7 )
  3776. //
  3777. if (($n_tok = count($a_toks)) < 6 ||
  3778. $a_toks[1] != "(" ||
  3779. $a_toks[3] != ";" ||
  3780. $a_toks[$n_tok-1] != ")")
  3781. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3782. array("SPEC"=>$s_spec,
  3783. "MSG"=>GetMessage(MSG_DER_FUNC_IF_FMT))));
  3784. else
  3785. {
  3786. $b_ok = true;
  3787. $s_fld_name = $a_toks[2];
  3788. $s_then_spec = $s_else_spec = "";
  3789. for ($ii = 4 ; $ii < $n_tok && $a_toks[$ii] != ';' ; $ii++)
  3790. $s_then_spec .= $a_toks[$ii];
  3791. if ($ii == $n_tok)
  3792. $b_ok = false;
  3793. else
  3794. {
  3795. //
  3796. // Concatenate tokens until the ')'.
  3797. // This provides the "else" spec.
  3798. //
  3799. for ( ; ++$ii < $n_tok && $a_toks[$ii] != ')' ; )
  3800. $s_else_spec .= $a_toks[$ii];
  3801. if ($ii == $n_tok)
  3802. $b_ok = false;
  3803. }
  3804. if ($b_ok)
  3805. {
  3806. if (!TestFieldEmpty($s_fld_name,$a_form_data,$s_mesg))
  3807. $s_fld_spec = $s_then_spec;
  3808. else
  3809. $s_fld_spec = $s_else_spec;
  3810. $s_value = GetDerivedValue($a_form_data,$s_fld_spec,$a_errors);
  3811. }
  3812. else
  3813. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3814. array("SPEC"=>$s_spec,
  3815. "MSG"=>GetMessage(MSG_DER_FUNC_IF_FMT))));
  3816. }
  3817. break;
  3818. case "size":
  3819. //
  3820. // "size" function: return size of uploaded file
  3821. //
  3822. // Example: size(fieldname)
  3823. //
  3824. // tokens are:
  3825. // 1 (
  3826. // 2 the field name for the file upload
  3827. // 3 )
  3828. //
  3829. if (count($a_toks) != 4 ||
  3830. $a_toks[1] != "(" ||
  3831. $a_toks[3] != ")")
  3832. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3833. array("SPEC"=>$s_spec,
  3834. "MSG"=>GetMessage(MSG_DER_FUNC_SIZE_FMT))));
  3835. elseif (($i_size = GetFileSize($a_toks[2])) !== false)
  3836. $s_value = "$i_size";
  3837. break;
  3838. case "ext":
  3839. //
  3840. // "ext" function: return filename extension of uploaded file
  3841. //
  3842. // Example: ext(fieldname)
  3843. //
  3844. // tokens are:
  3845. // 1 (
  3846. // 2 the field name for the file upload
  3847. // 3 )
  3848. //
  3849. if (count($a_toks) != 4 ||
  3850. $a_toks[1] != "(" ||
  3851. $a_toks[3] != ")")
  3852. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3853. array("SPEC"=>$s_spec,
  3854. "MSG"=>GetMessage(MSG_DER_FUNC_EXT_FMT))));
  3855. elseif (($s_name = GetFileName($a_toks[2])) !== false)
  3856. {
  3857. if (($i_pos = strrpos($s_name,".")) !== false)
  3858. $s_value = substr($s_name,$i_pos+1);
  3859. }
  3860. break;
  3861. case "ucase":
  3862. case "lcase":
  3863. //
  3864. // "ucase" and "lcase" functions: return field
  3865. // converted to upper or lower case
  3866. //
  3867. // Example: lcase(fieldname)
  3868. //
  3869. // tokens are:
  3870. // 1 (
  3871. // 2 the field name to convert
  3872. // 3 )
  3873. //
  3874. if (count($a_toks) != 4 ||
  3875. $a_toks[1] != "(" ||
  3876. $a_toks[3] != ")")
  3877. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3878. array("SPEC"=>$s_spec,
  3879. "MSG"=>GetMessage(MSG_DER_FUNC1_FMT,
  3880. array("FUNC"=>$a_toks[0])))));
  3881. elseif ($a_toks[0] == "ucase")
  3882. $s_value = strtoupper(GetFieldValue($a_toks[2],$a_form_data));
  3883. else
  3884. $s_value = strtolower(GetFieldValue($a_toks[2],$a_form_data));
  3885. break;
  3886. case "ltrim":
  3887. case "rtrim":
  3888. case "trim":
  3889. //
  3890. // trim functions: return field with whitespace removed
  3891. // from left (ltrim), right (rtrim), or both (trim)
  3892. // ends.
  3893. //
  3894. // Example: ltrim(fieldname)
  3895. //
  3896. // tokens are:
  3897. // 1 (
  3898. // 2 the field name to trim
  3899. // 3 )
  3900. //
  3901. if (count($a_toks) != 4 ||
  3902. $a_toks[1] != "(" ||
  3903. $a_toks[3] != ")")
  3904. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3905. array("SPEC"=>$s_spec,
  3906. "MSG"=>GetMessage(MSG_DER_FUNC1_FMT,
  3907. array("FUNC"=>$a_toks[0])))));
  3908. else
  3909. $s_value = $a_toks[0](GetFieldValue($a_toks[2],$a_form_data));
  3910. break;
  3911. case "ltrim0":
  3912. //
  3913. // ltrim0 function: return field with blanks and
  3914. // leading 0's removed from the left.
  3915. //
  3916. // Example: ltrim0(fieldname)
  3917. //
  3918. // tokens are:
  3919. // 1 (
  3920. // 2 the field name to trim
  3921. // 3 )
  3922. //
  3923. if (count($a_toks) != 4 ||
  3924. $a_toks[1] != "(" ||
  3925. $a_toks[3] != ")")
  3926. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3927. array("SPEC"=>$s_spec,
  3928. "MSG"=>GetMessage(MSG_DER_FUNC1_FMT,
  3929. array("FUNC"=>$a_toks[0])))));
  3930. else
  3931. {
  3932. $s_value = GetFieldValue($a_toks[2],$a_form_data);
  3933. $s_value = ltrim($s_value); // trim blanks on left
  3934. $i_len = strspn($s_value,"0");
  3935. //
  3936. // if the whole string is zeroes, make sure we leave
  3937. // one of them!
  3938. //
  3939. if ($i_len == strlen($s_value))
  3940. if (--$i_len < 0)
  3941. $i_len = 0;
  3942. $s_value = substr($s_value,$i_len);
  3943. }
  3944. break;
  3945. case "nextnum":
  3946. //
  3947. // "nextnum" function: return a unique number (next number)
  3948. //
  3949. // Usage: nextnum[(pad[,base])]
  3950. //
  3951. // Examples:
  3952. // %nextnum%
  3953. // %nextnum(8)%
  3954. // %nextnum(5;16)%
  3955. //
  3956. // You can provide a padding amount. In this case, the
  3957. // number is padded on the left with zeroes to the number
  3958. // of digits specified.
  3959. //
  3960. // You can also provide a base for your numbers. Valid
  3961. // values for base are 2 to 36, inclusive.
  3962. //
  3963. // tokens are:
  3964. // 1 (
  3965. // 2 the padding amount
  3966. // 3 ;
  3967. // 4 the base
  3968. // 5 )
  3969. //
  3970. $i_pad = 0; // no padding
  3971. $i_base = 10; // base 10
  3972. if (($n_tok = count($a_toks)) > 1)
  3973. {
  3974. if (($n_tok != 4 && $n_tok != 6) ||
  3975. $a_toks[1] != "(" ||
  3976. $a_toks[$n_tok-1] != ")")
  3977. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3978. array("SPEC"=>$s_spec,
  3979. "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T1)")));
  3980. if ($n_tok == 6 && $a_toks[3] != ";")
  3981. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3982. array("SPEC"=>$s_spec,
  3983. "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T2)")));
  3984. if (!is_numeric($a_toks[2]) ||
  3985. ($n_tok == 6 && !is_numeric($a_toks[4])))
  3986. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3987. array("SPEC"=>$s_spec,
  3988. "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T3)")));
  3989. $i_pad = intval($a_toks[2]);
  3990. if ($n_tok == 6)
  3991. {
  3992. $i_base = intval($a_toks[4]);
  3993. if ($i_base < 2 || $i_base > 36)
  3994. {
  3995. SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
  3996. array("SPEC"=>$s_spec,
  3997. "MSG"=>GetMessage(MSG_DER_FUNC_NEXTNUM_FMT)." (T4)")));
  3998. $i_base = 10;
  3999. }
  4000. }
  4001. $s_value = GetNextNum($i_pad,$i_base);
  4002. }
  4003. else
  4004. {
  4005. $s_value = GetNextNum($i_pad,$i_base);
  4006. }
  4007. break;
  4008. default:
  4009. SendAlert(GetMessage(MSG_UNK_VALUE_SPEC,
  4010. array("SPEC"=>$s_spec,"MSG"=>"")));
  4011. break;
  4012. }
  4013. }
  4014. else
  4015. SendAlert(GetMessage(MSG_UNK_VALUE_SPEC,array("SPEC"=>$s_spec,
  4016. "MSG"=>"")));
  4017. }
  4018. break;
  4019. }
  4020. return ($s_value);
  4021. }
  4022. //
  4023. // Return the next number or fail on error
  4024. //
  4025. function GetNextNum($i_pad,$i_base)
  4026. {
  4027. global $NEXT_NUM_FILE,$php_errormsg;
  4028. if (!isset($NEXT_NUM_FILE) || $NEXT_NUM_FILE === "")
  4029. {
  4030. ErrorWithIgnore("next_num_config",GetMessage(MSG_NO_NEXT_NUM_FILE));
  4031. exit;
  4032. }
  4033. if (($fp = @fopen($NEXT_NUM_FILE,"r+")) === false)
  4034. {
  4035. Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  4036. array("FILE"=>$NEXT_NUM_FILE,
  4037. "ACT"=>"open",
  4038. "ERR"=>$php_errormsg)));
  4039. exit;
  4040. }
  4041. if (!flock($fp,defined("LOCK_EX") ? LOCK_EX : 2))
  4042. {
  4043. Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  4044. array("FILE"=>$NEXT_NUM_FILE,
  4045. "ACT"=>"flock",
  4046. "ERR"=>$php_errormsg)));
  4047. exit;
  4048. }
  4049. //
  4050. // read the first line only
  4051. //
  4052. if (!feof($fp))
  4053. {
  4054. if (($s_line = fread($fp,1024)) === false)
  4055. $i_next = 1;
  4056. elseif (($i_next = intval($s_line)) <= 0)
  4057. $i_next = 1;
  4058. }
  4059. else
  4060. $i_next = 1;
  4061. if (rewind($fp) == 0)
  4062. {
  4063. Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  4064. array("FILE"=>$NEXT_NUM_FILE,
  4065. "ACT"=>"rewind",
  4066. "ERR"=>$php_errormsg)));
  4067. exit;
  4068. }
  4069. $s_ret = strval($i_next++);
  4070. if (fputs($fp,"$i_next\r\n") <= 0)
  4071. {
  4072. Error("next_num_file",GetMessage(MSG_NEXT_NUM_FILE,
  4073. array("FILE"=>$NEXT_NUM_FILE,
  4074. "ACT"=>"fputs",
  4075. "ERR"=>$php_errormsg)));
  4076. exit;
  4077. }
  4078. fclose($fp);
  4079. if ($i_base != 10)
  4080. {
  4081. $s_ret = base_convert($s_ret,10,$i_base);
  4082. $s_ret = strtoupper($s_ret); // always upper case if alphas are used
  4083. }
  4084. if ($i_pad != 0)
  4085. $s_ret = str_pad($s_ret,$i_pad,"0",STR_PAD_LEFT);
  4086. return ($s_ret);
  4087. }
  4088. //
  4089. // Return the value of an object or array as a string.
  4090. //
  4091. function GetObjectAsString($m_value)
  4092. {
  4093. ob_start();
  4094. print_r($m_value);
  4095. $s_ret = ob_get_contents();
  4096. ob_end_clean();
  4097. return ($s_ret);
  4098. }
  4099. //
  4100. // Return a Server or Environment variable value. Returns false if
  4101. // not found, otherwise a string value.
  4102. //
  4103. function GetEnvValue($s_name)
  4104. {
  4105. global $aServerVars,$aEnvVars;
  4106. if (isset($aEnvVars[$s_name]))
  4107. $m_value = $aEnvVars[$s_name];
  4108. elseif (isset($aServerVars[$s_name]))
  4109. $m_value = $aServerVars[$s_name];
  4110. //
  4111. // some values might not be strings - so convert
  4112. //
  4113. if (isset($m_value) && !is_scalar($m_value))
  4114. $m_value = GetObjectAsString($m_value);
  4115. return (isset($m_value) ? ((string) $m_value) : false);
  4116. }
  4117. //
  4118. // Test if a field is set in the given vars array or in the uploaded
  4119. // files.
  4120. //
  4121. function IsFieldSet($s_fld,$a_main_vars)
  4122. {
  4123. global $aFileVars;
  4124. if (isset($a_main_vars[$s_fld]))
  4125. return (true);
  4126. if (FILEUPLOADS)
  4127. {
  4128. if (isset($aFileVars[$s_fld]))
  4129. return (true);
  4130. if (IsSetSession("FormSavedFiles"))
  4131. {
  4132. $a_saved_files = GetSession("FormSavedFiles");
  4133. if (isset($a_saved_files[$s_fld]))
  4134. return (true);
  4135. }
  4136. }
  4137. return (false);
  4138. }
  4139. /*
  4140. * Function: IsFileField
  4141. * Parameters: $s_fld the field name
  4142. * Returns: bool true if this is a file upload field
  4143. * Description:
  4144. * Checks if a field is a file upload field (regardless of whether
  4145. * file uploads are being allowed, or whether the actual upload
  4146. * is valid in any way).
  4147. */
  4148. function IsFileField($s_fld)
  4149. {
  4150. global $aFileVars;
  4151. return (isset($aFileVars[$s_fld]));
  4152. }
  4153. //
  4154. // Delete the info for an uploaded file
  4155. //
  4156. function DeleteFileInfo($s_fld)
  4157. {
  4158. global $aFileVars;
  4159. global $aCleanedValues,$aRawDataValues,$aAllRawValues;
  4160. if (FILEUPLOADS)
  4161. {
  4162. if (IsSetSession("FormSavedFiles"))
  4163. {
  4164. $a_saved_files = GetSession("FormSavedFiles");
  4165. unset($a_saved_files[$s_fld]);
  4166. SetSession("FormSavedFiles",$a_saved_files);
  4167. }
  4168. if (isset($aFileVars[$s_fld]))
  4169. unset($aFileVars[$s_fld]);
  4170. //
  4171. // zap any "name_of" field that has been created
  4172. //
  4173. $s_name = "name_of_$s_fld";
  4174. unset($aCleanedValues[$s_name]);
  4175. unset($aRawDataValues[$s_name]);
  4176. unset($aAllRawValues[$s_name]);
  4177. }
  4178. }
  4179. //
  4180. // Return the info for the uploaded file, or false on error.
  4181. //
  4182. function GetFileInfo($s_fld)
  4183. {
  4184. global $aFileVars;
  4185. if (FILEUPLOADS)
  4186. {
  4187. //
  4188. // Must look at new file uploads first.
  4189. //
  4190. if (isset($aFileVars[$s_fld]) && !empty($aFileVars[$s_fld]))
  4191. $a_upload = $aFileVars[$s_fld];
  4192. elseif (IsSetSession("FormSavedFiles"))
  4193. {
  4194. $a_saved_files = GetSession("FormSavedFiles");
  4195. if (isset($a_saved_files[$s_fld]))
  4196. $a_upload = $a_saved_files[$s_fld];
  4197. }
  4198. }
  4199. if (isset($a_upload))
  4200. {
  4201. if (isset($a_upload["tmp_name"]) && !empty($a_upload["tmp_name"]) &&
  4202. isset($a_upload["name"]) && !empty($a_upload["name"]) &&
  4203. IsUploadedFile($a_upload))
  4204. return ($a_upload);
  4205. }
  4206. return (false);
  4207. }
  4208. //
  4209. // Return the original name of the uploaded file or false on error.
  4210. //
  4211. function GetFileName($s_fld)
  4212. {
  4213. if (($a_upload = GetFileInfo($s_fld)) !== false)
  4214. return ($a_upload["name"]);
  4215. return (false);
  4216. }
  4217. //
  4218. // Return the size of the uploaded file or false on error.
  4219. //
  4220. function GetFileSize($s_fld)
  4221. {
  4222. if (($a_upload = GetFileInfo($s_fld)) !== false)
  4223. return ($a_upload["size"]);
  4224. return (false);
  4225. }
  4226. //
  4227. // Return a field value. Empty string is returned if the field is
  4228. // not found. File fields return the original name of the uploaded file.
  4229. //
  4230. function GetFieldValue($s_fld,$a_main_vars,$s_array_sep = ";")
  4231. {
  4232. if (!isset($a_main_vars[$s_fld]))
  4233. {
  4234. if (($s_name = GetFileName($s_fld)) === false)
  4235. $s_name = "";
  4236. return ($s_name);
  4237. }
  4238. if (is_array($a_main_vars[$s_fld]))
  4239. return (implode($s_array_sep,$a_main_vars[$s_fld]));
  4240. else
  4241. return ((string) $a_main_vars[$s_fld]);
  4242. }
  4243. //
  4244. // Tests a field against an array of vars for emptyness.
  4245. // If the var isn't found there, then the POSTed files array is checked.
  4246. // Returns true if the field is empty (a specific error may
  4247. // be returned in the $s_mesg parameter).
  4248. //
  4249. function TestFieldEmpty($s_fld,$a_main_vars,&$s_mesg)
  4250. {
  4251. global $aFileVars;
  4252. $s_mesg = "";
  4253. $b_empty = TRUE;
  4254. if (!isset($a_main_vars[$s_fld]))
  4255. {
  4256. //
  4257. // Each file var is an array with these elements:
  4258. // "name" => The original name of the file on the client machine.
  4259. // "type" => The mime type of the file, if the browser provided this information.
  4260. // "tmp_name" => The temporary filename of the file in which the uploaded file was stored on the server.
  4261. // "error" => The error code associated with this file upload.
  4262. // NOTE: "error" was added in PHP 4.2.0
  4263. // "size" => The size, in bytes, of the uploaded file.
  4264. //
  4265. // Error codes (the constants are only available from PHP 4.3.0 so
  4266. // we have to use the raw numbers):
  4267. // UPLOAD_ERR_OK
  4268. // Value: 0; There is no error, the file uploaded with success.
  4269. // UPLOAD_ERR_INI_SIZE
  4270. // Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
  4271. // UPLOAD_ERR_FORM_SIZE
  4272. // Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.
  4273. // UPLOAD_ERR_PARTIAL
  4274. // Value: 3; The uploaded file was only partially uploaded.
  4275. // UPLOAD_ERR_NO_FILE
  4276. // Value: 4; No file was uploaded.
  4277. //
  4278. if (FILEUPLOADS)
  4279. {
  4280. if (IsSetSession("FormSavedFiles"))
  4281. {
  4282. $a_saved_files = GetSession("FormSavedFiles");
  4283. if (isset($a_saved_files[$s_fld]))
  4284. $a_upload = $a_saved_files[$s_fld];
  4285. elseif (isset($aFileVars[$s_fld]))
  4286. $a_upload = $aFileVars[$s_fld];
  4287. }
  4288. elseif (isset($aFileVars[$s_fld]))
  4289. $a_upload = $aFileVars[$s_fld];
  4290. }
  4291. if (isset($a_upload))
  4292. {
  4293. if (isset($a_upload["tmp_name"]) && !empty($a_upload["tmp_name"]) &&
  4294. isset($a_upload["name"]) && !empty($a_upload["name"]))
  4295. {
  4296. if (IsUploadedFile($a_upload))
  4297. $b_empty = false;
  4298. }
  4299. if ($b_empty && isset($a_upload["error"]))
  4300. switch ($a_upload["error"])
  4301. {
  4302. case 1:
  4303. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR1);
  4304. break;
  4305. case 2:
  4306. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR2);
  4307. break;
  4308. case 3:
  4309. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR3);
  4310. break;
  4311. case 4:
  4312. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR4);
  4313. break;
  4314. case 6:
  4315. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR6);
  4316. break;
  4317. case 7:
  4318. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR7);
  4319. break;
  4320. case 8:
  4321. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR8);
  4322. break;
  4323. default:
  4324. $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR_UNK,
  4325. array("ERRNO"=>$a_upload["error"]));
  4326. break;
  4327. }
  4328. }
  4329. }
  4330. else
  4331. $b_empty = FieldManager::IsEmpty($a_main_vars[$s_fld]);
  4332. return ($b_empty);
  4333. }
  4334. //
  4335. // Return a derived field value or value specification.
  4336. //
  4337. function GetDerivedValue($a_form_data,$s_word,&$a_errors)
  4338. {
  4339. $s_value = "";
  4340. //
  4341. // a field name or a value specification
  4342. // value specifications have the following format:
  4343. // %spec%
  4344. //
  4345. if (substr($s_word,0,1) == '%')
  4346. {
  4347. if (substr($s_word,-1,1) != '%')
  4348. {
  4349. SendAlert(GetMessage(MSG_INV_VALUE_SPEC,array("SPEC"=>$s_word)));
  4350. $s_value = $s_word;
  4351. }
  4352. else
  4353. {
  4354. $s_spec = substr($s_word,1,-1);
  4355. $s_value = ValueSpec($s_spec,$a_form_data,$a_errors);
  4356. }
  4357. }
  4358. else
  4359. {
  4360. $s_fld_name = $s_word;
  4361. //
  4362. // try form data first, then the environment/server data
  4363. //
  4364. if (IsFieldSet($s_fld_name,$a_form_data))
  4365. $s_value = GetFieldValue($s_fld_name,$a_form_data);
  4366. elseif (($s_value = GetEnvValue($s_fld_name)) === false)
  4367. $s_value = "";
  4368. $s_value = trim($s_value);
  4369. }
  4370. return ($s_value);
  4371. }
  4372. //
  4373. // Derive a value from the form data using the specification returned
  4374. // from ParseDerivation.
  4375. //
  4376. function DeriveValue($a_form_data,$a_value_spec,$s_name,&$a_errors)
  4377. {
  4378. $s_value = "";
  4379. for ($ii = 0 ; $ii < count($a_value_spec) ; $ii++)
  4380. {
  4381. switch ($a_value_spec[$ii])
  4382. {
  4383. case '+':
  4384. //
  4385. // concatenate with a single space between, but skip the space
  4386. // if the next field is empty
  4387. //
  4388. if ($ii < count($a_value_spec)-1)
  4389. {
  4390. $s_temp = GetDerivedValue($a_form_data,$a_value_spec[$ii+1],$a_errors);
  4391. if (!FieldManager::IsEmpty($s_temp))
  4392. $s_value .= ' ';
  4393. }
  4394. break;
  4395. case '.':
  4396. //
  4397. // concatenate with no space between
  4398. //
  4399. break;
  4400. case '*':
  4401. //
  4402. // concatenate with a single space between
  4403. //
  4404. $s_value .= ' ';
  4405. break;
  4406. default:
  4407. //
  4408. // a field name or a value specification
  4409. // value specifications have the following format:
  4410. // %name%
  4411. //
  4412. $s_value .= GetDerivedValue($a_form_data,$a_value_spec[$ii],$a_errors);
  4413. break;
  4414. }
  4415. }
  4416. return ($s_value);
  4417. }
  4418. //
  4419. // Create derived fields specified by the "derive_fields" value.
  4420. //
  4421. function CreateDerived($a_form_data)
  4422. {
  4423. if (isset($a_form_data["derive_fields"]))
  4424. {
  4425. $a_errors = array();
  4426. //
  4427. // get the list of derived field specifications
  4428. //
  4429. $a_list = TrimArray(explode(",",$a_form_data["derive_fields"]));
  4430. foreach ($a_list as $s_fld_spec)
  4431. {
  4432. if ($s_fld_spec === "")
  4433. //
  4434. // silently ignore empty derivations
  4435. //
  4436. continue;
  4437. if (($i_pos = strpos($s_fld_spec,"=")) === false)
  4438. {
  4439. $a_errors[] = $s_fld_spec;
  4440. continue;
  4441. }
  4442. $s_name = trim(substr($s_fld_spec,0,$i_pos));
  4443. $s_fld_spec = substr($s_fld_spec,$i_pos+1);
  4444. if (($a_value_spec = ParseDerivation($a_form_data,$s_fld_spec,
  4445. $s_name,$a_errors)) === false)
  4446. break;
  4447. $a_form_data[$s_name] = DeriveValue($a_form_data,$a_value_spec,$s_name,$a_errors);
  4448. }
  4449. if (count($a_errors) > 0)
  4450. {
  4451. SendAlert(GetMessage(MSG_DERIVED_INVALID).implode("\n",$a_errors));
  4452. Error("derivation_failure",GetMessage(MSG_INT_FORM_ERROR));
  4453. }
  4454. }
  4455. return ($a_form_data);
  4456. }
  4457. //
  4458. // To process the name specification for files and update the
  4459. // array of file variables accordingly.
  4460. //
  4461. function SetFileNames($s_name_spec,$a_order,$a_fields,$a_raw_fields,$a_all_raw_values,$a_file_vars)
  4462. {
  4463. $a_errors = array();
  4464. //
  4465. // get the list of file name derivations
  4466. //
  4467. $a_list = TrimArray(explode(",",$s_name_spec));
  4468. foreach ($a_list as $s_fld_spec)
  4469. {
  4470. if ($s_fld_spec === "")
  4471. //
  4472. // silently ignore empty file name derivations
  4473. //
  4474. continue;
  4475. if (($i_pos = strpos($s_fld_spec,"=")) === false)
  4476. {
  4477. $a_errors[] = $s_fld_spec;
  4478. continue;
  4479. }
  4480. $s_name = trim(substr($s_fld_spec,0,$i_pos));
  4481. $s_fld_spec = substr($s_fld_spec,$i_pos+1);
  4482. if (($a_value_spec = ParseDerivation($a_raw_fields,$s_fld_spec,
  4483. $s_name,$a_errors)) === false)
  4484. break;
  4485. if (isset($a_file_vars[$s_name]) && IsUploadedFile($a_file_vars[$s_name]))
  4486. {
  4487. //
  4488. // we create our own special entry in the file variable's data
  4489. //
  4490. $a_file_vars[$s_name]["new_name"] = DeriveValue($a_raw_fields,
  4491. $a_value_spec,$s_name,
  4492. $a_errors);
  4493. //
  4494. // we also create (derive) a new field called 'name_of_X'
  4495. // where X is the file fields's name
  4496. //
  4497. ProcessField("name_of_$s_name",$a_file_vars[$s_name]["new_name"],
  4498. $a_order,$a_fields,$a_raw_fields);
  4499. $a_all_raw_values["name_of_$s_name"] = $a_file_vars[$s_name]["new_name"];
  4500. }
  4501. /* This is annoying if a file upload is optional. Just ignore missing
  4502. file upload fields.
  4503. else
  4504. SendAlert(GetMessage(MSG_FILE_NAMES_NOT_FILE,
  4505. array("NAME"=>$s_name)));*/
  4506. }
  4507. if (count($a_errors) > 0)
  4508. {
  4509. SendAlert(GetMessage(MSG_FILE_NAMES_INVALID).implode("\n",$a_errors));
  4510. Error("file_names_derivation_failure",GetMessage(MSG_INT_FORM_ERROR));
  4511. }
  4512. return (array($a_order,$a_fields,$a_raw_fields,$a_all_raw_values,$a_file_vars));
  4513. }
  4514. //
  4515. // Process a list of attributes or options.
  4516. // Format for each attribute/option:
  4517. // name
  4518. // or
  4519. // name=value
  4520. //
  4521. // Values can be simple values or semicolon (;) separated lists:
  4522. // avalue
  4523. // value1;value2;value3;...
  4524. //
  4525. // Returns attribute/options in the associative array $a_attribs.
  4526. // Optionally, valid attributes can be provided in $a_valid_attribs
  4527. // (if empty, all attributes found are considered valid).
  4528. // Errors are returned in $a_errors.
  4529. //
  4530. function ProcessAttributeList($a_list,&$a_attribs,&$a_errors,
  4531. $a_valid_attribs = array())
  4532. {
  4533. $b_got_valid_list = (count($a_valid_attribs) > 0);
  4534. foreach ($a_list as $s_attrib)
  4535. {
  4536. //
  4537. // if the name begins with '.' then silently ignore it;
  4538. // this allows you to temporarily disable an option without
  4539. // getting an alert message
  4540. //
  4541. if (($i_pos = strpos($s_attrib,"=")) === false)
  4542. {
  4543. $s_name = trim($s_attrib);
  4544. if (empty($s_name) || $s_name[0] == '.')
  4545. continue;
  4546. //
  4547. // option is a simple "present" value
  4548. //
  4549. $a_attribs[$s_name] = true;
  4550. }
  4551. else
  4552. {
  4553. $s_name = trim(substr($s_attrib,0,$i_pos));
  4554. if (empty($s_name) || $s_name[0] == '.')
  4555. continue;
  4556. $s_value_list = substr($s_attrib,$i_pos+1);
  4557. if (($i_pos = strpos($s_value_list,";")) === false)
  4558. //
  4559. // single value
  4560. //
  4561. $a_attribs[$s_name] = trim($s_value_list);
  4562. else
  4563. //
  4564. // list of values
  4565. //
  4566. $a_attribs[$s_name] = TrimArray(explode(";",$s_value_list));
  4567. }
  4568. if ($b_got_valid_list && !isset($a_valid_attribs[$s_name]))
  4569. $a_errors[] = $s_name;
  4570. }
  4571. }
  4572. //
  4573. // Process the options specified in the form.
  4574. // Options can be specified in this format:
  4575. // option1,option2,option3,...
  4576. // Each option can be a simple word or a word and value:
  4577. // name
  4578. // name=value
  4579. // No name or value can contain a comma.
  4580. // Values can be simple values or semicolon (;) separated lists:
  4581. // avalue
  4582. // value1;value2;value3;...
  4583. // No value can contain a semicolon.
  4584. // Be careful of values beginning and ending with whitespace characters;
  4585. // they will be trimmed.
  4586. //
  4587. function ProcessOptions($s_name,$a_form_data,&$a_options,$a_valid_options)
  4588. {
  4589. $a_errors = array();
  4590. $a_options = array();
  4591. if (isset($a_form_data[$s_name]))
  4592. {
  4593. //
  4594. // get the options list and trim each one
  4595. //
  4596. $a_list = TrimArray(explode(",",$a_form_data[$s_name]));
  4597. ProcessAttributeList($a_list,$a_options,$a_errors,$a_valid_options);
  4598. }
  4599. if (count($a_errors) > 0)
  4600. SendAlert(GetMessage(MSG_OPTIONS_INVALID,array("OPT"=>$s_name)).
  4601. implode("\n",$a_errors));
  4602. }
  4603. //
  4604. // Process the mail_options specified in the form.
  4605. //
  4606. function ProcessMailOptions($a_form_data)
  4607. {
  4608. global $MAIL_OPTS,$VALID_MAIL_OPTIONS;
  4609. ProcessOptions("mail_options",$a_form_data,$MAIL_OPTS,$VALID_MAIL_OPTIONS);
  4610. }
  4611. //
  4612. // Check if an option is set
  4613. //
  4614. function IsMailOptionSet($s_name)
  4615. {
  4616. global $MAIL_OPTS;
  4617. return (isset($MAIL_OPTS[$s_name]));
  4618. }
  4619. //
  4620. // Return an option's value or NULL if not set.
  4621. //
  4622. function GetMailOption($s_name)
  4623. {
  4624. global $MAIL_OPTS;
  4625. return (isset($MAIL_OPTS[$s_name]) ? $MAIL_OPTS[$s_name] : NULL);
  4626. }
  4627. //
  4628. // Process the crm_options specified in the form.
  4629. //
  4630. function ProcessCRMOptions($a_form_data)
  4631. {
  4632. global $CRM_OPTS,$VALID_CRM_OPTIONS;
  4633. ProcessOptions("crm_options",$a_form_data,$CRM_OPTS,$VALID_CRM_OPTIONS);
  4634. }
  4635. //
  4636. // Check if an option is set
  4637. //
  4638. function IsCRMOptionSet($s_name)
  4639. {
  4640. global $CRM_OPTS;
  4641. return (isset($CRM_OPTS[$s_name]));
  4642. }
  4643. //
  4644. // Return an option's value or NULL if not set.
  4645. //
  4646. function GetCRMOption($s_name)
  4647. {
  4648. global $CRM_OPTS;
  4649. return (isset($CRM_OPTS[$s_name]) ? $CRM_OPTS[$s_name] : NULL);
  4650. }
  4651. //
  4652. // Check if a field is in the mail exclusion list.
  4653. //
  4654. function IsMailExcluded($s_name)
  4655. {
  4656. $a_list = GetMailOption("Exclude");
  4657. if (!isset($a_list))
  4658. return (false);
  4659. if (is_array($a_list))
  4660. return (in_array($s_name,$a_list));
  4661. else
  4662. return ($s_name === $a_list);
  4663. }
  4664. //
  4665. // Process the autorespond specified in the form.
  4666. //
  4667. function ProcessAROptions($a_form_data)
  4668. {
  4669. global $AR_OPTS,$VALID_AR_OPTIONS;
  4670. ProcessOptions("autorespond",$a_form_data,$AR_OPTS,$VALID_AR_OPTIONS);
  4671. }
  4672. //
  4673. // Check if an option is set
  4674. //
  4675. function IsAROptionSet($s_name)
  4676. {
  4677. global $AR_OPTS;
  4678. return (isset($AR_OPTS[$s_name]));
  4679. }
  4680. //
  4681. // Return an option's value or NULL if not set.
  4682. //
  4683. function GetAROption($s_name)
  4684. {
  4685. global $AR_OPTS;
  4686. return (isset($AR_OPTS[$s_name]) ? $AR_OPTS[$s_name] : NULL);
  4687. }
  4688. //
  4689. // Process the mail_options specified in the form.
  4690. //
  4691. function ProcessFilterOptions($a_form_data)
  4692. {
  4693. global $FILTER_OPTS,$VALID_FILTER_OPTIONS;
  4694. ProcessOptions("filter_options",$a_form_data,$FILTER_OPTS,$VALID_FILTER_OPTIONS);
  4695. }
  4696. //
  4697. // Check if an option is set
  4698. //
  4699. function IsFilterOptionSet($s_name)
  4700. {
  4701. global $FILTER_OPTS;
  4702. return (isset($FILTER_OPTS[$s_name]));
  4703. }
  4704. //
  4705. // Return an option's value or NULL if not set.
  4706. //
  4707. function GetFilterOption($s_name)
  4708. {
  4709. global $FILTER_OPTS;
  4710. return (isset($FILTER_OPTS[$s_name]) ? $FILTER_OPTS[$s_name] : NULL);
  4711. }
  4712. //
  4713. // Lookup a filter attribute for the given filter.
  4714. // Return it's value or false if not set.
  4715. //
  4716. function GetFilterAttrib($s_filter,$s_attrib)
  4717. {
  4718. global $FILTER_ATTRIBS,$FILTER_ATTRIBS_LOOKUP;
  4719. if (!isset($FILTER_ATTRIBS[$s_filter]))
  4720. //
  4721. // no attributes for the filter
  4722. //
  4723. return (false);
  4724. if (!isset($FILTER_ATTRIBS_LOOKUP[$s_filter]))
  4725. {
  4726. //
  4727. // the attributes have not yet been parsed - create the lookup table
  4728. //
  4729. $a_list = TrimArray(explode(",",$FILTER_ATTRIBS[$s_filter]));
  4730. $FILTER_ATTRIBS_LOOKUP[$s_filter] = array();
  4731. $a_errors = array();
  4732. ProcessAttributeList($a_list,$FILTER_ATTRIBS_LOOKUP[$s_filter],$a_errors);
  4733. }
  4734. //
  4735. // perform the lookup and return the value
  4736. //
  4737. if (!isset($FILTER_ATTRIBS_LOOKUP[$s_filter][$s_attrib]))
  4738. return (false);
  4739. return ($FILTER_ATTRIBS_LOOKUP[$s_filter][$s_attrib]);
  4740. }
  4741. //
  4742. // Check the filter attributes for the given filter.
  4743. // Return true if the given attribute is set otherwise false.
  4744. //
  4745. function IsFilterAttribSet($s_filter,$s_attrib)
  4746. {
  4747. return (GetFilterAttrib($s_filter,$s_attrib));
  4748. }
  4749. //
  4750. // Process the given .ini file.
  4751. //
  4752. function ProcessFormIniFile($s_file)
  4753. {
  4754. global $EMAIL_ADDRS,$ValidEmails;
  4755. $a_sections = parse_ini_file($s_file,TRUE);
  4756. //
  4757. // from PHP 5.2.7, parse_ini_file returns false on syntax problems
  4758. // prior to that, an empty array. So, on previous versions of PHP
  4759. // we cannot detect an actual error (an empty array is perfectly valid).
  4760. //
  4761. if ($a_sections === false)
  4762. Error("bad_ini",GetMessage(MSG_INI_PARSE_ERROR,array("FILE"=>$s_file)));
  4763. elseif (empty($a_sections))
  4764. SendAlert(GetMessage(MSG_INI_PARSE_WARN,array("FILE"=>$s_file)),false,true);
  4765. if (DB_SEE_INI)
  4766. {
  4767. //
  4768. // just display the ini file
  4769. //
  4770. $s_text = "<p><b>The following settings were found in the file '$s_file':</b></p>";
  4771. foreach ($a_sections as $s_sect=>$a_settings)
  4772. {
  4773. $s_text .= "<p>[$s_sect]\n";
  4774. foreach ($a_settings as $s_name=>$s_value)
  4775. $s_text .= "$s_name = \"$s_value\"\n";
  4776. $s_text .= "</p>";
  4777. }
  4778. CreatePage($s_text,"Debug Output - INI File Display");
  4779. exit;
  4780. }
  4781. //
  4782. // Load the email_addresses section.
  4783. //
  4784. if (isset($a_sections["email_addresses"]))
  4785. {
  4786. $EMAIL_ADDRS = $a_sections["email_addresses"];
  4787. //
  4788. // make these addresses valid
  4789. //
  4790. foreach ($EMAIL_ADDRS as $s_list)
  4791. $ValidEmails->AddAddresses($s_list);
  4792. }
  4793. //
  4794. // Process special fields
  4795. //
  4796. if (isset($a_sections["special_fields"]))
  4797. {
  4798. foreach ($a_sections["special_fields"] as $s_name=>$m_value)
  4799. {
  4800. if (IsSpecialField($s_name))
  4801. {
  4802. SetSpecialField($s_name,$m_value);
  4803. //
  4804. // if this is the recipients, cc, or bcc field,
  4805. // make the addresses valid
  4806. //
  4807. if ($s_name === "recipients" || $s_name === "cc" || $s_name === "bcc")
  4808. //
  4809. // coming from the INI file, the values can only be strings
  4810. //
  4811. if (is_string($m_value))
  4812. $ValidEmails->AddAddresses($m_value);
  4813. }
  4814. //
  4815. // check for multiple valued special fields
  4816. //
  4817. if (($a_multi_fld = IsSpecialMultiField($s_name)) !== false)
  4818. SetSpecialMultiField($a_multi_fld[0],$a_multi_fld[1],$m_value);
  4819. }
  4820. }
  4821. }
  4822. //
  4823. // UnMangle an email address
  4824. //
  4825. function UnMangle($email)
  4826. {
  4827. global $EMAIL_ADDRS;
  4828. //
  4829. // map from a name to the real email address
  4830. //
  4831. if (isset($EMAIL_ADDRS[$email]))
  4832. $email = $EMAIL_ADDRS[$email];
  4833. //
  4834. // unmangle
  4835. //
  4836. if (AT_MANGLE != "")
  4837. $email = str_replace(AT_MANGLE,"@",$email);
  4838. return ($email);
  4839. }
  4840. //
  4841. // Check a list of email addresses (comma separated); returns a list
  4842. // of valid email addresses (comma separated).
  4843. // The list can be an array of comma separated lists.
  4844. // The return value is true if there is at least one valid email address.
  4845. //
  4846. function CheckEmailAddress($m_addr,&$s_valid,&$s_invalid,$b_check = true)
  4847. {
  4848. global $ValidEmails;
  4849. $s_invalid = $s_valid = "";
  4850. if (is_array($m_addr))
  4851. {
  4852. $a_list = array();
  4853. foreach ($m_addr as $s_addr_list)
  4854. $a_list = array_merge($a_list,TrimArray(explode(",",$s_addr_list)));
  4855. }
  4856. else
  4857. $a_list = TrimArray(explode(",",$m_addr));
  4858. $a_invalid = array();
  4859. $n_empty = 0;
  4860. for ($ii = 0 ; $ii < count($a_list) ; $ii++)
  4861. {
  4862. if ($a_list[$ii] === "")
  4863. {
  4864. //
  4865. // ignore, but count empty addresses
  4866. //
  4867. $n_empty++;
  4868. continue;
  4869. }
  4870. $s_email = UnMangle($a_list[$ii]);
  4871. //
  4872. // UnMangle works with INI files too, and a single
  4873. // word can expand to a list of email addresses.
  4874. //
  4875. $a_this_list = TrimArray(explode(",",$s_email));
  4876. foreach ($a_this_list as $s_email)
  4877. {
  4878. if ($s_email === "")
  4879. {
  4880. //
  4881. // ignore, but count empty addresses
  4882. //
  4883. $n_empty++;
  4884. continue;
  4885. }
  4886. if ($b_check)
  4887. $b_is_valid = $ValidEmails->CheckAddress($s_email);
  4888. else
  4889. $b_is_valid = true;
  4890. if ($b_is_valid)
  4891. {
  4892. if (empty($s_valid))
  4893. $s_valid = $s_email;
  4894. else
  4895. $s_valid .= ",".$s_email;
  4896. }
  4897. else
  4898. $a_invalid[] = $s_email;
  4899. }
  4900. }
  4901. //
  4902. // just ignore empty recipients unless there are *no* valid recipients
  4903. //
  4904. if (empty($s_valid) && $n_empty > 0)
  4905. $a_invalid[] = GetMessage(MSG_EMPTY_ADDRESSES,array("COUNT"=>$n_empty));
  4906. if (count($a_invalid) > 0)
  4907. $s_invalid = implode(",",$a_invalid);
  4908. return (!empty($s_valid));
  4909. }
  4910. //
  4911. // Redirect to another URL
  4912. //
  4913. function Redirect($url,$title)
  4914. {
  4915. //
  4916. // for browsers without cookies enabled, append the Session ID
  4917. //
  4918. if (session_id() !== "")
  4919. $url = AddURLParams($url,session_name()."=".urlencode(session_id()));
  4920. elseif (defined("SID"))
  4921. $url = AddURLParams($url,SID);
  4922. //FMDebug("Before redirecting, FormData = ".(isset($_SESSION["FormData"]) ? var_export($_SESSION["FormData"],true) : "NULL"));
  4923. //
  4924. // this is probably a good idea to ensure the session data
  4925. // is written away
  4926. //
  4927. if (function_exists('session_write_close'))
  4928. session_write_close();
  4929. header("Location: $url");
  4930. //
  4931. // if the header doesn't work, try JavaScript.
  4932. // if that doesn't work, provide a manual link
  4933. //
  4934. $s_text = GetMessage(MSG_PLSWAIT_REDIR)."\n\n";
  4935. $s_text .= "<script language=\"JavaScript\" type=\"text/javascript\">";
  4936. $s_text .= "window.location.href = '$url';";
  4937. $s_text .= "</script>";
  4938. $s_text .= "\n\n".GetMessage(MSG_IFNOT_REDIR,array("URL"=>$url));
  4939. CreatePage($s_text,$title);
  4940. exit;
  4941. }
  4942. class JSON
  4943. {
  4944. function _Format($m_val)
  4945. {
  4946. if (is_bool($m_val))
  4947. $s_value = ($m_val) ? "true" : "false";
  4948. elseif (is_string($m_val))
  4949. $s_value = '"'.addslashes($m_val).'"';
  4950. elseif (is_numeric($m_val))
  4951. $s_value = $m_val;
  4952. elseif (is_array($m_val))
  4953. $s_value = $this->_FormatArray($m_val);
  4954. else
  4955. $s_value = "null";
  4956. return ($s_value);
  4957. }
  4958. function _FormatArray($a_array)
  4959. {
  4960. if ($this->_IsNumericArray($a_array))
  4961. {
  4962. $a_values = array();
  4963. foreach ($a_array as $m_val)
  4964. $a_values[] = $this->_Format($m_val);
  4965. $s_value = "[".implode(",",$a_values)."]";
  4966. }
  4967. else
  4968. {
  4969. //
  4970. // associative arrays are objects
  4971. //
  4972. $s_value = $this->MakeObject($a_array);
  4973. }
  4974. return ($s_value);
  4975. }
  4976. //
  4977. // check if we have a numeric array or an associative array
  4978. // numeric arrays may have holes; numeric array indexes must
  4979. // be integers
  4980. //
  4981. function _IsNumericArray($a_data)
  4982. {
  4983. if (empty($a_data))
  4984. return (true); // empty array - treat as numeric
  4985. //
  4986. // check all the keys for numeric
  4987. //
  4988. $a_keys = array_keys($a_data);
  4989. foreach ($a_keys as $m_index)
  4990. if (!is_int($m_index))
  4991. return (false);
  4992. return (true);
  4993. }
  4994. function MakeObject($a_data)
  4995. {
  4996. $a_members = array();
  4997. foreach ($a_data as $s_key=>$m_val)
  4998. $a_members[] = '"'.$s_key.'":'.$this->_Format($m_val);
  4999. return ("{".implode(",",$a_members)."}");
  5000. }
  5001. }
  5002. function CORS_Response()
  5003. {
  5004. header('Access-Control-Allow-Origin: *');
  5005. header('Access-Control-Max-Age: 36000');
  5006. header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
  5007. header('Access-Control-Allow-Headers: X-Requested-With');
  5008. }
  5009. function JSON_Result($s_result,$a_data = array())
  5010. {
  5011. global $aGetVars;
  5012. FMDebug("Sending JSON_Result: $s_result");
  5013. $a_data["Result"] = $s_result;
  5014. $json = new JSON();
  5015. $s_ret = $json->MakeObject($a_data);
  5016. CORS_Response();
  5017. //
  5018. // handle JSONP request
  5019. //
  5020. if (isset($aGetVars['callback']) && $aGetVars['callback'] != '')
  5021. {
  5022. header('Content-Type: text/javascript; charset=utf-8');
  5023. $s_ret = $aGetVars['callback']."($s_ret);";
  5024. FMDebug('JSONP request callback='.$aGetVars['callback']);
  5025. }
  5026. else
  5027. {
  5028. header('Content-Encoding: utf-8');
  5029. header('Content-Type: application/json; charset=utf-8');
  5030. }
  5031. FMDebug("JSON_Result output: ".$s_ret);
  5032. echo $s_ret;
  5033. }
  5034. //
  5035. // JoinLines is just like "implode" except that it checks
  5036. // the end of each array for the separator already being
  5037. // there. This allows us to join a mixture of mail
  5038. // header lines (already terminated) with body lines.
  5039. // This logic works if HEAD_CRLF, for example, is the same
  5040. // as BODY_LF (i.e. both "\r\n") or if BODY_LF is the
  5041. // same as the last character in HEAD_CRLF (i.e.
  5042. // HEAD_CRLF = "\r\n" and BODY_LF = "\n").
  5043. // Other value combinations may break things.
  5044. //
  5045. function JoinLines($s_sep,$a_lines)
  5046. {
  5047. $s_str = "";
  5048. if (($i_sep_len = strlen($s_sep)) == 0)
  5049. //
  5050. // no separator
  5051. //
  5052. return (implode("",$a_lines));
  5053. $n_lines = count($a_lines);
  5054. for ($ii = 0 ; $ii < $n_lines ; $ii++)
  5055. {
  5056. $s_line = $a_lines[$ii];
  5057. if (substr($s_line,-$i_sep_len) == $s_sep)
  5058. $s_str .= $s_line;
  5059. else
  5060. {
  5061. $s_str .= $s_line;
  5062. //
  5063. // don't append a separator to the last line
  5064. //
  5065. if ($ii < $n_lines-1)
  5066. $s_str .= $s_sep;
  5067. }
  5068. }
  5069. return ($s_str);
  5070. }
  5071. //
  5072. // Re-orders an array of email headers into the
  5073. // order recommended by RFC822, section 4.1:
  5074. // It is recommended that, if present,
  5075. // headers be sent in the order "Return-
  5076. // Path", "Received", "Date", "From", "Subject",
  5077. // "Sender", "To", "cc", etc.
  5078. //
  5079. // Note that RFC822 is obsoleted by RFC2822 and
  5080. // the latter states that field order doesn't
  5081. // matter (except for some tracing fields).
  5082. // However, a FormMail user reported that Yahoo doesn't like
  5083. // email where the CC header appears before the From
  5084. // header. So, as always, we try to work with broken
  5085. // servers too...
  5086. //
  5087. // Returns an array indexed by the require numerical
  5088. // order. Each element is an array containing the
  5089. // header value (name,value pair).
  5090. //
  5091. function OrderHeaders($a_headers)
  5092. {
  5093. //
  5094. // we list the headers we're responsible for
  5095. // in the order suggested
  5096. //
  5097. $a_ordering = array("From","Subject","To","Cc","Bcc","Reply-To");
  5098. $a_ordered_headers = array();
  5099. foreach ($a_ordering as $s_name)
  5100. {
  5101. if (isset($a_headers[$s_name]))
  5102. {
  5103. $a_ordered_headers[] = array($s_name=>$a_headers[$s_name]);
  5104. unset($a_headers[$s_name]);
  5105. }
  5106. }
  5107. //
  5108. // now add in the remaining headers
  5109. //
  5110. foreach ($a_headers as $s_name=>$s_value)
  5111. $a_ordered_headers[] = array($s_name=>$a_headers[$s_name]);
  5112. return ($a_ordered_headers);
  5113. }
  5114. //
  5115. // Makes a mail header field body "safe".
  5116. // This simply places a backslash in front of every double-quote.
  5117. // There's probably more we could do if required, but this
  5118. // attempts to provide the same protection that was in the first
  5119. // version of FormMail. In that version, every incoming
  5120. // field had double-quotes replaced with single quotes.
  5121. // That processing is no longer performed, and this
  5122. // function is used to protect against potential attacks in
  5123. // header fields - not by replacing double quotes with single quotes,
  5124. // but by using the backslash "quoting" feature of RFC2822.
  5125. //
  5126. // This code could be improved by parsing the header and rewriting
  5127. // it to be valid, possibly removing junk.
  5128. //
  5129. // That's a lot of code, though!
  5130. //
  5131. function SafeHeader($s_str)
  5132. {
  5133. return (str_replace('"','\\"',$s_str));
  5134. }
  5135. //
  5136. // makes a string safe to put as words in a header
  5137. //
  5138. function SafeHeaderWords($s_str)
  5139. {
  5140. //
  5141. // We zap various characters and replace them with a question mark.
  5142. // Also, we don't handle quoted strings, which are valid words.
  5143. //
  5144. $s_specials = '()<>@,;:\\".[]'; // special characters defined by RFC822
  5145. $s_str = preg_replace('/[[:cntrl:]]+/',"?",$s_str); // zap all control chars
  5146. $s_str = preg_replace("/[".preg_quote($s_specials,"/")."]/","?",$s_str); // zap all specials
  5147. return ($s_str);
  5148. }
  5149. //
  5150. // makes a string safe to put as a quoted string in a header
  5151. //
  5152. function SafeHeaderQString($s_str)
  5153. {
  5154. return (str_replace('"','\\"',
  5155. str_replace("\\","\\\\",
  5156. str_replace("\r"," ",
  5157. str_replace("\r\n"," ",$s_str)))));
  5158. }
  5159. //
  5160. // makes a string safe to put in a header comment
  5161. //
  5162. function SafeHeaderComment($s_str)
  5163. {
  5164. return (str_replace("(","\\(",
  5165. str_replace(")","\\)",
  5166. str_replace("\\","\\\\",
  5167. str_replace("\r"," ",
  5168. str_replace("\r\n"," ",$s_str))))));
  5169. }
  5170. //
  5171. // makes a string safe to put in a header as an email address
  5172. //
  5173. function SafeHeaderEmail($s_str)
  5174. {
  5175. //
  5176. // An email address is made up of local and domain parts
  5177. // each of these is made up of "words" separated by "."
  5178. // each "word" can be a sequence of characters excluding
  5179. // specials, space and control characters OR it can be
  5180. // a quoted string.
  5181. //
  5182. // The correct processing would be to completely
  5183. // parse the address, strip junk, double-quote
  5184. // words that need to be turned into quote strings,
  5185. // and return a well-formed email address.
  5186. //
  5187. // That's a lot of code!
  5188. //
  5189. // So, instead, we opt for stripping out control characters.
  5190. //
  5191. $s_str = preg_replace('/[[:cntrl:]]+/',"",$s_str); // zap all control chars
  5192. return ($s_str);
  5193. }
  5194. //
  5195. // Expands an array of mail headers into mail header lines.
  5196. //
  5197. function ExpandMailHeaders($a_headers,$b_fold = false)
  5198. {
  5199. $s_hdrs = "";
  5200. $a_ordered_headers = OrderHeaders($a_headers);
  5201. for ($ii = 0 ; $ii < count($a_ordered_headers) ; $ii++)
  5202. {
  5203. foreach ($a_ordered_headers[$ii] as $s_name=>$s_value)
  5204. if ($s_name != "")
  5205. {
  5206. if ($s_hdrs != "")
  5207. $s_hdrs .= HEAD_CRLF;
  5208. if ($b_fold)
  5209. $s_hdrs .= HeaderFolding($s_name.": ".$s_value);
  5210. else
  5211. $s_hdrs .= $s_name.": ".$s_value;
  5212. }
  5213. }
  5214. //FMDebug("Headers are: $s_hdrs");
  5215. return ($s_hdrs);
  5216. }
  5217. //
  5218. // Expands an array of mail headers into an array containing header lines.
  5219. //
  5220. function ExpandMailHeadersArray($a_headers)
  5221. {
  5222. $a_hdrs = array();
  5223. $a_ordered_headers = OrderHeaders($a_headers);
  5224. for ($ii = 0 ; $ii < count($a_ordered_headers) ; $ii++)
  5225. {
  5226. foreach ($a_ordered_headers[$ii] as $s_name=>$s_value)
  5227. if ($s_name != "")
  5228. $a_hdrs[] = $s_name.": ".$s_value.HEAD_CRLF;
  5229. }
  5230. return ($a_hdrs);
  5231. }
  5232. //
  5233. // Low-level email send function; either calls PHP's mail function
  5234. // or uses the PEAR Mail object.
  5235. // NOTE: for some errors, there's no point trying to email
  5236. // an alert message! So, in these cases, we just display the error to
  5237. // the user.
  5238. // $s_options are ignored for PEAR sending.
  5239. //
  5240. function DoMail($s_to,$s_subject,$s_mesg,$a_headers,$s_options)
  5241. {
  5242. global $PEAR_SMTP_HOST,$PEAR_SMTP_PORT,$PEAR_SMTP_USER,$PEAR_SMTP_PWD;
  5243. //
  5244. // Encode the subject line.
  5245. // Ideally, we want to encode the relevant parts of To, From, Cc,
  5246. // Reply-To, and this is the right place to do it.
  5247. // However, it's another 1000 lines of code!
  5248. // So, we must compromise the code quality because of this cost.
  5249. // We encode subject here, and we encode the From line where it's
  5250. // created. The rest remain for a future version where code size
  5251. // can be controlled.
  5252. //
  5253. $s_subject = EncodeHeaderText($s_subject);
  5254. if (isset($PEAR_SMTP_HOST) && !empty($PEAR_SMTP_HOST))
  5255. {
  5256. //
  5257. // Note that PEAR Mail seems to take responsibility for header line folding
  5258. //
  5259. require_once("Mail.php");
  5260. $a_params = array( "host"=>$PEAR_SMTP_HOST,
  5261. "port"=>$PEAR_SMTP_PORT);
  5262. if (isset($PEAR_SMTP_USER) && !empty($PEAR_SMTP_USER))
  5263. {
  5264. $a_params["auth"] = TRUE;
  5265. $a_params["username"] = $PEAR_SMTP_USER;
  5266. $a_params["password"] = $PEAR_SMTP_PWD;
  5267. }
  5268. $mailer = Mail::factory("smtp",$a_params);
  5269. if (!is_object($mailer))
  5270. {
  5271. ShowError("pear_error",GetMessage(MSG_PEAR_OBJ),FALSE,FALSE);
  5272. exit;
  5273. }
  5274. if (strtolower(get_class($mailer)) === 'pear_error')
  5275. {
  5276. ShowError("pear_error",$mailer->getMessage(),FALSE,FALSE);
  5277. exit;
  5278. }
  5279. if (!isset($a_headers['To']) && !isset($a_headers['to']))
  5280. $a_headers['To'] = SafeHeader($s_to);
  5281. if (!isset($a_headers['Subject']) && !isset($a_headers['subject']))
  5282. $a_headers['Subject'] = SafeHeader($s_subject);
  5283. $res = $mailer->send($s_to,$a_headers,$s_mesg);
  5284. if ($res === TRUE)
  5285. return (TRUE);
  5286. global $aAlertInfo;
  5287. $aAlertInfo[] = GetMessage(MSG_PEAR_ERROR,array("MSG"=>$res->getMessage()));
  5288. return (FALSE);
  5289. }
  5290. else
  5291. {
  5292. //$s_subject = HeaderFolding($s_subject,RFCLINELEN-10); // "Subject: " is about 10 chars
  5293. //
  5294. // Notes from Feb 2010....
  5295. //
  5296. // PHP's mail function (tested in version 5.2.6) does folding of the
  5297. // To line and the Subject line.
  5298. // If we do it, then things break.
  5299. //
  5300. // This area is quite confusing. It's not clear whether the script
  5301. // should be folding header lines or whether the MTA should do it.
  5302. // We *do know* (as stated above) that folding To and Subject breaks things.
  5303. //
  5304. // But folding other header lines properly, seems to be OK.
  5305. //
  5306. // However, for years FormMail never did header line folding (except for the
  5307. // soft line breaks inserted by the quoted_printable_encode function we had used),
  5308. // and we didn't seem to get any reports of breakage (except for problems
  5309. // with the quoted_printable_encode soft line breaks!).
  5310. //
  5311. // So, even though we've implemented all the code for header line folding,
  5312. // we'll not use it.
  5313. // No header line folding will be performed in version 8.22 onwards.
  5314. //
  5315. if ($s_options !== "")
  5316. return (mail($s_to,$s_subject,$s_mesg,ExpandMailHeaders($a_headers),$s_options));
  5317. else
  5318. return (mail($s_to,$s_subject,$s_mesg,ExpandMailHeaders($a_headers)));
  5319. }
  5320. }
  5321. //
  5322. // Send an email
  5323. //
  5324. function SendCheckedMail($to,$subject,$mesg,$sender,$a_headers = array())
  5325. {
  5326. global $PEAR_SMTP_HOST;
  5327. $b_f_option = false;
  5328. $b_form_option = IsMailOptionSet("SendMailFOption"); // this is superseded, but still supported
  5329. if (SENDMAIL_F_OPTION || $b_form_option)
  5330. {
  5331. if (empty($sender))
  5332. {
  5333. //
  5334. // SENDMAIL_F_OPTION with no sender is silently ignored
  5335. //
  5336. if ($b_form_option)
  5337. {
  5338. //
  5339. // form has specified SendMailFOption, but there's no
  5340. // sender address
  5341. //
  5342. static $b_in_here = false;
  5343. global $SERVER;
  5344. if (!$b_in_here) // prevent infinite recursion
  5345. {
  5346. $b_in_here = true;
  5347. SendAlert(GetMessage(MSG_NO_FOPT_ADDR));
  5348. $b_in_here = false;
  5349. }
  5350. //
  5351. // if there's no from address, create a dummy one
  5352. //
  5353. $sender = "dummy@".(isset($SERVER) ? $SERVER : "UnknownServer");
  5354. $a_headers['From'] = $sender;
  5355. $b_f_option = true;
  5356. }
  5357. }
  5358. else
  5359. $b_f_option = true;
  5360. }
  5361. if (INI_SET_FROM && !empty($sender))
  5362. ini_set('sendmail_from',$sender);
  5363. return (DoMail($to,$subject,$mesg,$a_headers,($b_f_option ? "-f$sender" : "")));
  5364. }
  5365. //
  5366. // Send an alert email
  5367. //
  5368. function SendAlert($s_error,$b_filter = true,$b_non_error = false)
  5369. {
  5370. global $SPECIAL_VALUES,$FORMATTED_INPUT,$FROM_USER,$aServerVars,$aStrippedFormVars;
  5371. global $aAlertInfo,$aCleanedValues,$aFieldOrder,$sHTMLCharSet;
  5372. $s_error = str_replace("\n",BODY_LF,$s_error);
  5373. $b_got_filter = GetFilterSpec($s_filter_name,$a_filter_list);
  5374. //
  5375. // if there is a filter specified and we're not sending the alert
  5376. // through the filter, don't show the user's data. This is
  5377. // on the assumption that the filter is an encryption program; so,
  5378. // we don't want to send the user's data in clear text inside the
  5379. // alerts.
  5380. //
  5381. $b_show_data = true;
  5382. if ($b_got_filter && !$b_filter)
  5383. $b_show_data = false;
  5384. $s_form_subject = $s_alert_to = "";
  5385. $b_check = true;
  5386. //
  5387. // might be too early to have $SPECIAL_VALUES set, so
  5388. // look in the form vars too
  5389. //
  5390. if (isset($SPECIAL_VALUES["alert_to"]))
  5391. $s_alert_to = trim($SPECIAL_VALUES["alert_to"]);
  5392. if (empty($s_alert_to) && isset($aStrippedFormVars["alert_to"]))
  5393. $s_alert_to = trim($aStrippedFormVars["alert_to"]);
  5394. if (isset($SPECIAL_VALUES["subject"]))
  5395. $s_form_subject = trim($SPECIAL_VALUES["subject"]);
  5396. if (empty($s_form_subject) && isset($aStrippedFormVars["subject"]))
  5397. $s_form_subject = trim($aStrippedFormVars["subject"]);
  5398. if (empty($s_alert_to))
  5399. {
  5400. $s_alert_to = DEF_ALERT;
  5401. $b_check = false;
  5402. }
  5403. if (!empty($s_alert_to))
  5404. {
  5405. $s_from_addr = $s_from = "";
  5406. $a_headers = array();
  5407. if (isset($FROM_USER) && !empty($FROM_USER))
  5408. {
  5409. if ($FROM_USER != "NONE")
  5410. {
  5411. $a_headers['From'] = $FROM_USER;
  5412. $s_from = "From: $FROM_USER";
  5413. $s_from_addr = $FROM_USER;
  5414. }
  5415. }
  5416. else
  5417. {
  5418. global $SERVER;
  5419. $s_from_addr = "FormMail@".$SERVER;
  5420. $a_headers['From'] = $s_from_addr;
  5421. $s_from = "From: $s_from_addr";
  5422. }
  5423. $s_mesg = "To: ".UnMangle($s_alert_to).BODY_LF;
  5424. //
  5425. // if a language pack has been included, a lot of error messages
  5426. // may need the character set to be provided.
  5427. // If that's available from the language pack, use it,
  5428. // otherwise, if it's a mail_option, use it from there.
  5429. //
  5430. $s_charset = "";
  5431. if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  5432. $s_charset = $sHTMLCharSet;
  5433. else if (IsMailOptionSet("CharSet"))
  5434. $s_charset = GetMailOption("CharSet");
  5435. //
  5436. // Alerts are plain text emails, so convert any HTML entities
  5437. // back to their original characters. Note, this will only work on PHP
  5438. // version 4.3.0 and above.
  5439. //
  5440. if (function_exists("html_entity_decode"))
  5441. $s_error = @html_entity_decode($s_error,ENT_COMPAT,$s_charset);
  5442. if ($s_charset !== "")
  5443. $a_headers['Content-Type'] = SafeHeader("text/plain; charset=$s_charset");
  5444. if (!empty($s_from))
  5445. $s_mesg .= $s_from.BODY_LF;
  5446. $s_mesg .= BODY_LF;
  5447. if (count($aAlertInfo) > 0)
  5448. {
  5449. if ($b_show_data)
  5450. {
  5451. $s_error .= BODY_LF.GetMessage(MSG_MORE_INFO).BODY_LF;
  5452. $s_error .= implode(BODY_LF,$aAlertInfo);
  5453. }
  5454. else
  5455. $s_error .= BODY_LF.GetMessage(MSG_INFO_STOPPED).BODY_LF;
  5456. }
  5457. //
  5458. // some fields aren't security issues - show those in the alert
  5459. //
  5460. $a_safe_fields = array(
  5461. "email: ".$SPECIAL_VALUES["email"],
  5462. "realname: ".$SPECIAL_VALUES["realname"],
  5463. );
  5464. $s_safe_data = implode(BODY_LF,$a_safe_fields);
  5465. if ($b_non_error)
  5466. {
  5467. $s_preamble = $s_error.BODY_LF.BODY_LF;
  5468. $s_mesg .= $s_preamble;
  5469. $s_subj = GetMessage(MSG_FM_ALERT);
  5470. if (!empty($s_form_subject))
  5471. $s_subj .= " ($s_form_subject)";
  5472. }
  5473. else
  5474. {
  5475. $s_preamble = GetMessage(MSG_FM_ERROR_LINE).BODY_LF.
  5476. $s_error.BODY_LF.BODY_LF;
  5477. $s_mesg .= $s_preamble;
  5478. $s_subj = GetMessage(MSG_FM_ERROR);
  5479. if (!empty($s_form_subject))
  5480. $s_subj .= " ($s_form_subject)";
  5481. $s_mesg .= $s_safe_data;
  5482. $s_mesg .= BODY_LF.BODY_LF;
  5483. if ($b_show_data)
  5484. $s_mesg .= implode(BODY_LF,$FORMATTED_INPUT);
  5485. else
  5486. $s_mesg .= GetMessage(MSG_USERDATA_STOPPED);
  5487. }
  5488. /*
  5489. * We only need to filter the form fields if the filter that
  5490. * is specified is an encrypting filter.
  5491. */
  5492. if ($b_filter && $b_got_filter &&
  5493. IsFilterAttribSet($SPECIAL_VALUES["filter"],"Encrypts"))
  5494. {
  5495. $s_new_mesg = $s_preamble.$s_safe_data;
  5496. $s_new_mesg .= BODY_LF.BODY_LF;
  5497. if ($a_filter_list !== false)
  5498. {
  5499. //
  5500. // just filter the critical fields
  5501. //
  5502. list($s_unfiltered,$s_filtered_results) =
  5503. GetFilteredOutput($aFieldOrder,$aCleanedValues,
  5504. $s_filter_name,$a_filter_list);
  5505. $s_new_mesg .= $s_unfiltered;
  5506. }
  5507. else
  5508. {
  5509. //
  5510. // filter everything
  5511. //
  5512. $s_filtered_results = Filter($s_filter_name,$s_mesg);
  5513. }
  5514. $s_new_mesg .= GetMessage(MSG_FILTERED,array("FILTER"=>$s_filter_name)).
  5515. BODY_LF.BODY_LF.
  5516. $s_filtered_results;
  5517. $s_mesg = $s_new_mesg;
  5518. }
  5519. $s_mesg .= BODY_LF;
  5520. if (isset($aServerVars['HTTP_REFERER']))
  5521. $s_mesg .= "Referring page was ".$aServerVars['HTTP_REFERER'];
  5522. elseif (isset($SPECIAL_VALUES['this_form']) && $SPECIAL_VALUES['this_form'] !== "")
  5523. $s_mesg .= "Referring form was ".$SPECIAL_VALUES['this_form'];
  5524. $s_mesg .= BODY_LF;
  5525. if (isset($aServerVars['SERVER_NAME']))
  5526. $s_mesg .= "SERVER_NAME was ".$aServerVars['SERVER_NAME'].BODY_LF;
  5527. if (isset($aServerVars['REQUEST_URI']))
  5528. $s_mesg .= "REQUEST_URI was ".$aServerVars['REQUEST_URI'].BODY_LF;
  5529. $s_mesg .= BODY_LF;
  5530. if (isset($aServerVars['REMOTE_ADDR']))
  5531. $s_mesg .= "User IP address was ".$aServerVars['REMOTE_ADDR'].BODY_LF;
  5532. if (isset($aServerVars['HTTP_USER_AGENT']))
  5533. $s_mesg .= "User agent was ".$aServerVars['HTTP_USER_AGENT'].BODY_LF;
  5534. if ($b_check)
  5535. {
  5536. if (CheckEmailAddress($s_alert_to,$s_valid,$s_invalid))
  5537. return (SendCheckedMail($s_valid,$s_subj,$s_mesg,$s_from_addr,$a_headers));
  5538. }
  5539. else
  5540. return (SendCheckedMail($s_alert_to,$s_subj,$s_mesg,$s_from_addr,$a_headers));
  5541. }
  5542. return (false);
  5543. }
  5544. //
  5545. // Read the lines in a file and return an array.
  5546. // Each line is stripped of line termination characters.
  5547. //
  5548. function ReadLines($fp)
  5549. {
  5550. $a_lines = array();
  5551. while (!feof($fp))
  5552. {
  5553. $s_line = fgets($fp,4096);
  5554. //
  5555. // strip carriage returns and line feeds
  5556. //
  5557. $s_line = str_replace("\r","",$s_line);
  5558. $s_line = str_replace("\n","",$s_line);
  5559. $a_lines[] = $s_line;
  5560. }
  5561. return ($a_lines);
  5562. }
  5563. //
  5564. // Open a URL and return the data from it as a string or array of lines.
  5565. // Returns false on failure ($s_error has the error string)
  5566. //
  5567. function GetURL($s_url,&$s_error,$b_ret_lines = false,$n_depth = 0)
  5568. {
  5569. global $php_errormsg,$aServerVars,$sUserAgent;
  5570. global $AUTHENTICATE,$AUTH_USER,$AUTH_PW;
  5571. //
  5572. // open the URL with the same session as we have
  5573. //
  5574. if (session_id() !== "")
  5575. $s_url = AddURLParams($s_url,session_name()."=".urlencode(session_id()));
  5576. if (defined("SID"))
  5577. $s_url = AddURLParams($s_url,SID);
  5578. $http_get = new HTTPGet($s_url);
  5579. //
  5580. // Determine authentication requirements
  5581. //
  5582. if ($AUTHENTICATE !== "" || $AUTH_USER !== "" || $AUTH_PW !== "")
  5583. {
  5584. if ($AUTHENTICATE === "")
  5585. $http_get->SetAuthentication("Basic",$AUTH_USER,$AUTH_PW);
  5586. else
  5587. $http_get->SetAuthenticationLine($AUTHENTICATE);
  5588. }
  5589. else
  5590. {
  5591. $a_parts = $http_get->GetURLSplit();
  5592. if (isset($a_parts["user"]) || isset($a_parts["pass"]))
  5593. {
  5594. $s_auth_user = isset($a_parts["user"]) ? $a_parts["user"] : "";
  5595. $s_auth_pass = isset($a_parts["pass"]) ? $a_parts["pass"] : "";
  5596. }
  5597. else
  5598. {
  5599. $s_auth_type = isset($aServerVars["PHP_AUTH_TYPE"]) ? $aServerVars["PHP_AUTH_TYPE"] : "";
  5600. $s_auth_user = isset($aServerVars["PHP_AUTH_USER"]) ? $aServerVars["PHP_AUTH_USER"] : "";
  5601. $s_auth_pass = isset($aServerVars["PHP_AUTH_PW"]) ? $aServerVars["PHP_AUTH_PW"] : "";
  5602. }
  5603. if (!isset($s_auth_type) || $s_auth_type === "")
  5604. $s_auth_type = "Basic";
  5605. if ($s_auth_user !== "" || $s_auth_pass !== "")
  5606. $http_get->SetAuthentication($s_auth_type,$s_auth_user,$s_auth_pass);
  5607. }
  5608. //
  5609. // set the user agent
  5610. //
  5611. $http_get->SetAgent($sUserAgent);
  5612. //
  5613. // resolve the name now so the DNS cache can be written to the session
  5614. //
  5615. $http_get->Resolve();
  5616. //
  5617. // Since we might be opening a URL within the same session, we can
  5618. // get locks. So, close the session for writing to prevent this.
  5619. //
  5620. $b_closed = false;
  5621. if (function_exists('session_write_close'))
  5622. {
  5623. session_write_close();
  5624. $b_closed = true;
  5625. //ob_flush(); // this prevents automatic redirects if $TEMPLATEURL
  5626. // is in use and JavaScript is switched off
  5627. }
  5628. $m_buf = FALSE;
  5629. //FMDebug("Begin read");
  5630. if (($a_lines = $http_get->Read()) === FALSE)
  5631. {
  5632. $http_get->Close();
  5633. //
  5634. // get the error code and send the appropriate alert
  5635. //
  5636. list($i_error,$i_sys_err,$s_sys_msg) = $http_get->GetError();
  5637. switch ($i_error)
  5638. {
  5639. case $http_get->nErrParse:
  5640. $s_error = GetMessage(MSG_URL_PARSE);
  5641. break;
  5642. case $http_get->nErrScheme:
  5643. $a_parts = $http_get->GetURLSplit();
  5644. $s_error = GetMessage(MSG_URL_SCHEME,array("SCHEME"=>$a_parts["scheme"]));
  5645. break;
  5646. default:
  5647. $s_error = GetMessage(MSG_SOCKET,
  5648. array("ERRNO"=>$i_sys_err,
  5649. "ERRSTR"=>$s_sys_msg,
  5650. "PHPERR"=>isset($php_errormsg) ? $php_errormsg : ""));
  5651. break;
  5652. }
  5653. }
  5654. else
  5655. {
  5656. $http_get->Close();
  5657. //
  5658. // check the HTTP response for actual status. Anything outside
  5659. // 200-299 is a failure, but we also handle redirects.
  5660. //
  5661. list($i_http_code,$s_http_status) = $http_get->GetHTTPStatus();
  5662. if ($i_http_code < 200 || $i_http_code > 299)
  5663. {
  5664. switch ($i_http_code)
  5665. {
  5666. case 300: // multiple choices (we'll take the first)
  5667. case 301: // moved permanently
  5668. case 302: // found
  5669. case 303: // see other
  5670. case 307: // temporary redirect
  5671. //
  5672. // a "location" header must be present for us to continue
  5673. // In the case of infinite redirects, we need to stop.
  5674. // So, we limit to a maximum of 10 redirects.
  5675. //
  5676. if ($n_depth < 10)
  5677. {
  5678. if (($s_location = $http_get->FindHeader("location")) !== false)
  5679. {
  5680. FMDebug("Redirect from '$s_url' to '$s_location'");
  5681. $m_buf = GetURL($s_location,$s_error,$b_ret_lines,$n_depth+1);
  5682. $b_closed = false;
  5683. break;
  5684. }
  5685. FMDebug("Redirect FAILED - no location header");
  5686. }
  5687. else
  5688. FMDebug("Redirect FAILED depth=$n_depth");
  5689. // FALL THRU
  5690. default:
  5691. $s_error = GetMessage(MSG_GETURL_OPEN,array("STATUS"=>$s_http_status));
  5692. break;
  5693. }
  5694. }
  5695. elseif ($b_ret_lines)
  5696. $m_buf = $a_lines;
  5697. else
  5698. //
  5699. // return lines as one big string buffer
  5700. //
  5701. $m_buf = implode("",$a_lines);
  5702. }
  5703. //
  5704. // re-open our session
  5705. //
  5706. if ($b_closed)
  5707. session_start();
  5708. return ($m_buf);
  5709. }
  5710. //
  5711. // Write to the debug log if it exists and is writable.
  5712. //
  5713. function FMDebug($s_mesg)
  5714. {
  5715. static $fDebug = NULL;
  5716. if (!isset($fDebug))
  5717. {
  5718. $fDebug = false; // only initialize once
  5719. $s_dir = GetTempDir(); // look for the debug log file in the temp directory
  5720. $s_db_file = "$s_dir/fmdebug.log";
  5721. //
  5722. // we only open an existing file - we don't create one
  5723. //
  5724. if (file_exists($s_db_file))
  5725. if (($fDebug = fopen($s_db_file,"a")) === false)
  5726. return;
  5727. }
  5728. if ($fDebug !== false)
  5729. {
  5730. fwrite($fDebug,date('r').": ".$s_mesg."\n");
  5731. fflush($fDebug);
  5732. }
  5733. }
  5734. /*
  5735. * Class: NetIO
  5736. * Description:
  5737. * A class to provide internet input/output capabilities.
  5738. * Use as a base class for more specific functions.
  5739. */
  5740. class NetIO
  5741. {
  5742. var $_sHost;
  5743. var $_iPort;
  5744. var $_sPrefix;
  5745. var $_iConnTimeout;
  5746. var $_fSock;
  5747. var $_aIPs;
  5748. var $_iError = 0;
  5749. var $_iSysErr;
  5750. var $_sSysMesg;
  5751. var $nErrInit = -1; // not initialized
  5752. var $nErrRead = -2; // read error
  5753. var $nErrWrite = -3; // write error
  5754. var $nErrWriteShort = -4; // failed to write all bytes
  5755. var $nErrSocket = -100; // error in socket open
  5756. function NetIO($s_host = NULL,$i_port = NULL,$s_prefix = "")
  5757. {
  5758. if (isset($s_host))
  5759. $this->_sHost = $s_host;
  5760. if (isset($i_port))
  5761. $this->_iPort = $i_port;
  5762. $this->_sPrefix = $s_prefix;
  5763. $this->_iConnTimeout = 30;
  5764. $this->_iSysErr = 0;
  5765. $this->_sSysMesg = "";
  5766. }
  5767. function _SetError($i_error,$i_sys_err = 0,$s_sys_mesg = "")
  5768. {
  5769. $this->_iError = $i_error;
  5770. $this->_iSysErr = $i_sys_err;
  5771. $this->_sSysMesg = $s_sys_mesg;
  5772. return (FALSE);
  5773. }
  5774. function IsError()
  5775. {
  5776. return ($this->_iError != 0 ? TRUE : FALSE);
  5777. }
  5778. function ClearError()
  5779. {
  5780. $this->_SetError(0);
  5781. }
  5782. function GetError()
  5783. {
  5784. return (array($this->_iError,$this->_iSysErr,$this->_sSysMesg));
  5785. }
  5786. function SetHost($s_host)
  5787. {
  5788. $this->_sHost = $s_host;
  5789. }
  5790. function SetPort($i_port)
  5791. {
  5792. $this->_iPort = $i_port;
  5793. }
  5794. function SetConnectionTimeout($i_secs)
  5795. {
  5796. $this->_iConnTimeout = $i_secs;
  5797. }
  5798. function SetPrefix($s_prefix)
  5799. {
  5800. $this->_sPrefix = $s_prefix;
  5801. }
  5802. function GetHost()
  5803. {
  5804. return (isset($this->_sHost) ? $this->_sHost : "");
  5805. }
  5806. function GetPort()
  5807. {
  5808. return (isset($this->_iPort) ? $this->_iPort : 0);
  5809. }
  5810. function GetPrefix()
  5811. {
  5812. return ($this->_sPrefix);
  5813. }
  5814. function GetConnectionTimeout()
  5815. {
  5816. return ($this->_iConnTimeout);
  5817. }
  5818. function _CacheIt()
  5819. {
  5820. FMDebug("Caching ".implode(",",$this->_aIPs));
  5821. if (IsSetSession("FormNetIODNSCache"))
  5822. $a_cache = GetSession("FormNetIODNSCache");
  5823. else
  5824. $a_cache = array();
  5825. $a_cache[$this->_sHost] = $this->_aIPs;
  5826. SetSession("FormNetIODNSCache",$a_cache);
  5827. }
  5828. /*
  5829. * Some versions of PHP seem to have a major slowdown when resolving
  5830. * names with gethostbyname (5 seconds with PHP 4.3.9).
  5831. * So, in the case of multi-page forms using MULTIFORMURL, we get a big speed up
  5832. * by caching the IP address of the server.
  5833. */
  5834. function _CheckCache()
  5835. {
  5836. if (!IsSetSession("FormNetIODNSCache"))
  5837. return (FALSE);
  5838. $a_cache = GetSession("FormNetIODNSCache");
  5839. if (!is_array($a_cache) || !isset($a_cache[$this->_sHost]) || !is_array($a_cache[$this->_sHost]))
  5840. return (FALSE);
  5841. $this->_aIPs = $a_cache[$this->_sHost];
  5842. return (TRUE);
  5843. }
  5844. function Resolve()
  5845. {
  5846. $this->ClearError();
  5847. if (!isset($this->_sHost))
  5848. return ($this->_SetError($this->nErrInit));
  5849. if ($this->_CheckCache())
  5850. return (TRUE);
  5851. FMDebug("Start resolve of ".$this->_sHost);
  5852. //
  5853. // if host is an actual IP address, then it is returned unchanged, which is good!
  5854. //
  5855. if (($a_ip_list = gethostbynamel($this->_sHost)) === FALSE)
  5856. {
  5857. FMDebug("Resolve failed");
  5858. return ($this->_SetError($this->nErrInit,0,
  5859. GetMessage(MSG_RESOLVE,array("NAME"=>$this->_sHost))));
  5860. }
  5861. FMDebug("Done resolve: ".implode(",",$a_ip_list));
  5862. $this->_aIPs = $a_ip_list;
  5863. $this->_CacheIt();
  5864. return (TRUE);
  5865. }
  5866. function _SSLOpen($s_ip,&$errno,&$errstr,$i_timeout)
  5867. {
  5868. FMDebug("Using _SSLOpen (stream_socket_client), SNI, host=".$this->GetHost());
  5869. $context = stream_context_create();
  5870. $result = stream_context_set_option($context,'ssl','verify_host',true);
  5871. $result = stream_context_set_option($context,'ssl','verify_peer',false);
  5872. $result = stream_context_set_option($context,'ssl','allow_self_signed',true);
  5873. $result = stream_context_set_option($context,'ssl','SNI_enabled',true);
  5874. $result = stream_context_set_option($context,'ssl','SNI_server_name',$this->GetHost());
  5875. //
  5876. // Note that even if SNI fails, the socket will still open, but the
  5877. // web server should send a 400 error.
  5878. //
  5879. return (stream_socket_client($this->GetPrefix().$s_ip.":".$this->GetPort(),
  5880. $errno,$errstr,$i_timeout,STREAM_CLIENT_CONNECT,$context));
  5881. }
  5882. function Open()
  5883. {
  5884. $this->ClearError();
  5885. if (!isset($this->_sHost) || !isset($this->_iPort))
  5886. return ($this->_SetError($this->nErrInit));
  5887. if (!$this->Resolve())
  5888. return (FALSE);
  5889. FMDebug("Starting socket open");
  5890. $f_sock = FALSE;
  5891. //
  5892. // Now, run through the list of IPs until we find one that connects.
  5893. // However, this can cause problems with SNI in SSL/TLS connections.
  5894. // If there is only one IP address, use the host name.
  5895. // Otherwise, if we can specify SNI and it's an SSL connection
  5896. // use streams, otherwise try each IP individually.
  5897. //
  5898. if (count($this->_aIPs) == 1)
  5899. {
  5900. FMDebug("Trying host ".$this->_sHost.", timeout ".$this->GetConnectionTimeout());
  5901. $f_sock = @fsockopen($this->GetPrefix().$this->_sHost,$this->GetPort(),
  5902. $errno,$errstr,$this->GetConnectionTimeout());
  5903. }
  5904. else
  5905. {
  5906. foreach ($this->_aIPs as $s_ip)
  5907. {
  5908. FMDebug("Trying IP $s_ip, timeout ".$this->GetConnectionTimeout());
  5909. if (IsPHPAtLeast("5.3.2") && substr($this->GetPrefix(),0,3) == "ssl")
  5910. {
  5911. if (($f_sock = $this->_SSLOpen($s_ip,$errno,$errstr,
  5912. $this->GetConnectionTimeout())) !== FALSE)
  5913. break;
  5914. }
  5915. elseif (($f_sock = @fsockopen($this->GetPrefix().$s_ip,$this->GetPort(),
  5916. $errno,$errstr,$this->GetConnectionTimeout())) !== FALSE)
  5917. break;
  5918. }
  5919. }
  5920. if ($f_sock === FALSE)
  5921. {
  5922. FMDebug("open failed: $errno $errstr");
  5923. return ($this->_SetError($this->nErrSocket,$errno,$errstr));
  5924. }
  5925. $this->_fSock = $f_sock;
  5926. FMDebug("Done socket open");
  5927. return (TRUE);
  5928. }
  5929. function Read()
  5930. {
  5931. $this->ClearError();
  5932. $a_lines = array();
  5933. while (($s_line = fgets($this->_fSock)) !== FALSE)
  5934. $a_lines[] = $s_line;
  5935. FMDebug("Read ".count($a_lines)." lines");
  5936. return ($a_lines);
  5937. }
  5938. function Write($s_str,$b_flush = TRUE)
  5939. {
  5940. $this->ClearError();
  5941. if (!isset($this->_fSock))
  5942. return ($this->_SetError($this->nErrInit));
  5943. if (($n_write = fwrite($this->_fSock,$s_str)) === FALSE)
  5944. return ($this->_SetError($this->nErrWrite));
  5945. if ($n_write != strlen($s_str))
  5946. return ($this->_SetError($this->nErrWriteShort));
  5947. if ($b_flush)
  5948. if (fflush($this->_fSock) === FALSE)
  5949. return ($this->_SetError($this->nErrWriteShort));
  5950. return (TRUE);
  5951. }
  5952. function Close()
  5953. {
  5954. if (isset($this->_fSock))
  5955. {
  5956. fclose($this->_fSock);
  5957. unset($this->_fSock);
  5958. }
  5959. }
  5960. };
  5961. /*
  5962. * Class: HTTPGet
  5963. * Description:
  5964. * A class that implements HTTP GET method.
  5965. */
  5966. class HTTPGet extends NetIO
  5967. {
  5968. var $_sURL;
  5969. var $_aURLSplit;
  5970. var $_sRequest;
  5971. var $_aResponse;
  5972. var $_aRespHeaders;
  5973. var $_sAuthLine;
  5974. var $_sAuthType;
  5975. var $_sAuthUser;
  5976. var $_sAuthPass;
  5977. var $_sAgent;
  5978. var $nErrParse = -1000; // failed to parse URL
  5979. var $nErrScheme = -1001; // unsupported URL scheme
  5980. function HTTPGet($s_url = "")
  5981. {
  5982. NetIO::NetIO();
  5983. $this->_aURLSplit = array();
  5984. if (($this->_sURL = $s_url) !== "")
  5985. $this->_SplitURL();
  5986. }
  5987. function _SplitURL()
  5988. {
  5989. FMDebug("URL: ".$this->_sURL);
  5990. if (($this->_aURLSplit = parse_url($this->_sURL)) === FALSE)
  5991. {
  5992. $this->_aURLSplit = array();
  5993. return ($this->_SetError($this->nErrParse));
  5994. }
  5995. return (TRUE);
  5996. }
  5997. function GetURLSplit()
  5998. {
  5999. return ($this->_aURLSplit);
  6000. }
  6001. function SetURL($s_url)
  6002. {
  6003. $this->_aURLSplit = array();
  6004. $this->_sURL = $s_url;
  6005. return ($this->_SplitURL());
  6006. }
  6007. function _Init()
  6008. {
  6009. if (!isset($this->_aURLSplit["host"]))
  6010. return ($this->_SetError($this->nErrInit));
  6011. $this->SetHost($this->_aURLSplit["host"]);
  6012. $i_port = 80;
  6013. if (isset($this->_aURLSplit["scheme"]))
  6014. {
  6015. switch (strtolower($this->_aURLSplit["scheme"]))
  6016. {
  6017. case "http":
  6018. break;
  6019. case "https":
  6020. $i_port = 443;
  6021. break;
  6022. default:
  6023. return ($this->_SetError($this->nErrScheme));
  6024. }
  6025. }
  6026. if (isset($this->_aURLSplit["port"]))
  6027. $i_port = $this->_aURLSplit["port"];
  6028. if ($i_port == 443)
  6029. //
  6030. // we require ssl:// for port 443
  6031. //
  6032. $this->SetPrefix("ssl://");
  6033. $this->SetPort($i_port);
  6034. return (TRUE);
  6035. }
  6036. function _SendRequest()
  6037. {
  6038. FMDebug("Path: ".$this->_aURLSplit["path"]);
  6039. if (!isset($this->_aURLSplit["path"]) || $this->_aURLSplit["path"] === "")
  6040. $s_path = "/"; // default path
  6041. else
  6042. $s_path = $this->_aURLSplit["path"];
  6043. if (isset($this->_aURLSplit["query"]))
  6044. {
  6045. //
  6046. // add the query to the path
  6047. // Note that parse_url decodes the query string (urldecode), so
  6048. // we need to split it into its component parameters
  6049. // are re-encode their values. Calling urlencode($this->_aURLSplit["query"])
  6050. // encodes the '=' between parameters and this breaks things.
  6051. //
  6052. $a_params = explode('&',$this->_aURLSplit["query"]);
  6053. foreach ($a_params as $i_idx=>$s_param)
  6054. {
  6055. if (($i_pos = strpos($s_param,"=")) === false)
  6056. $a_params[$i_idx] = urlencode($s_param);
  6057. else
  6058. $a_params[$i_idx] = substr($s_param,0,$i_pos).'='.
  6059. urlencode(substr($s_param,$i_pos+1));
  6060. }
  6061. $s_path .= "?".implode('&',$a_params);
  6062. }
  6063. //
  6064. // add the fragment to the path.
  6065. //
  6066. if (isset($this->_aURLSplit["fragment"]))
  6067. $s_path .= '#'.urlencode($this->_aURLSplit["fragment"]);
  6068. //
  6069. // build the request
  6070. //
  6071. $s_req = "GET $s_path HTTP/1.0\r\n";
  6072. //
  6073. // Add authentication
  6074. //
  6075. if (isset($this->_sAuthLine))
  6076. $s_req .= "Authorization: $this->_sAuthLine\r\n";
  6077. elseif (isset($this->_sAuthType))
  6078. $s_req .= "Authorization: ".$this->_sAuthType." ".
  6079. base64_encode($this->_sAuthUser.":".$this->_sAuthPass)."\r\n";
  6080. //
  6081. // Specify the host name
  6082. //
  6083. $s_req .= "Host: ".$this->GetHost()."\r\n";
  6084. //
  6085. // Specify the user agent
  6086. //
  6087. if (isset($this->_sAgent))
  6088. $s_req .= "User-Agent: ".$this->_sAgent."\r\n";
  6089. //
  6090. // Accept any output
  6091. //
  6092. $s_req .= "Accept: */*\r\n";
  6093. //
  6094. // End of request headers
  6095. //
  6096. $s_req .= "\r\n";
  6097. $this->_sRequest = $s_req;
  6098. return (parent::Write($s_req));
  6099. }
  6100. function _GetResponse()
  6101. {
  6102. FMDebug("Reading");
  6103. if (($a_lines = parent::Read()) === FALSE)
  6104. return (FALSE);
  6105. $this->_aRespHeaders = $this->_aResponse = array();
  6106. $b_body = FALSE;
  6107. for ($ii = 0 ; $ii < count($a_lines) ; $ii++)
  6108. {
  6109. if ($b_body)
  6110. {
  6111. //FMDebug("Body line: ".rtrim($a_lines[$ii]));
  6112. $this->_aResponse[] = $a_lines[$ii];
  6113. }
  6114. elseif ($a_lines[$ii] == "\r\n" || $a_lines[$ii] == "\n")
  6115. $b_body = TRUE;
  6116. else
  6117. {
  6118. //FMDebug("Header line: ".rtrim($a_lines[$ii]));
  6119. $this->_aRespHeaders[] = $a_lines[$ii];
  6120. }
  6121. }
  6122. return (TRUE);
  6123. }
  6124. function GetResponseHeaders()
  6125. {
  6126. return ($this->_aRespHeaders);
  6127. }
  6128. function FindHeader($s_name)
  6129. {
  6130. $s_name = strtolower($s_name);
  6131. $i_len = strlen($s_name);
  6132. for ($ii = 0 ; $ii < count($this->_aRespHeaders) ; $ii++)
  6133. {
  6134. $s_line = $this->_aRespHeaders[$ii];
  6135. if (($s_hdr = substr($s_line,0,$i_len)) !== false)
  6136. {
  6137. $s_hdr = strtolower($s_hdr);
  6138. if ($s_hdr === $s_name && substr($s_line,$i_len,1) === ":")
  6139. return (trim(substr($s_line,$i_len+1)));
  6140. }
  6141. }
  6142. return (false);
  6143. }
  6144. function GetHTTPStatus()
  6145. {
  6146. $i_http_code = 0;
  6147. $s_status = "";
  6148. for ($ii = 0 ; $ii < count($this->_aRespHeaders) ; $ii++)
  6149. {
  6150. $s_line = $this->_aRespHeaders[$ii];
  6151. if (substr($s_line,0,4) == "HTTP")
  6152. {
  6153. $i_pos = strpos($s_line," ");
  6154. $s_status = substr($s_line,$i_pos+1);
  6155. $i_end_pos = strpos($s_status," ");
  6156. if ($i_end_pos === false)
  6157. $i_end_pos = strlen($s_status);
  6158. $i_http_code = (int) substr($s_status,0,$i_end_pos);
  6159. }
  6160. }
  6161. return (array($i_http_code,$s_status));
  6162. }
  6163. function Resolve()
  6164. {
  6165. if (!$this->_Init())
  6166. return (FALSE);
  6167. return (parent::Resolve());
  6168. }
  6169. function Read()
  6170. {
  6171. if (!$this->_Init())
  6172. return (FALSE);
  6173. FMDebug("Init done");
  6174. if (!$this->Open())
  6175. return (FALSE);
  6176. FMDebug("Open done");
  6177. if (!$this->_SendRequest())
  6178. return (FALSE);
  6179. FMDebug("Send done");
  6180. if (!$this->_GetResponse())
  6181. return (FALSE);
  6182. FMDebug("Get done");
  6183. $this->Close();
  6184. return ($this->_aResponse);
  6185. }
  6186. function SetAuthenticationLine($s_auth)
  6187. {
  6188. $this->_sAuthLine = $s_auth;
  6189. }
  6190. function SetAuthentication($s_type,$s_user,$s_pass)
  6191. {
  6192. $this->_sAuthType = $s_type;
  6193. $this->_sAuthUser = $s_user;
  6194. $this->_sAuthPass = $s_pass;
  6195. }
  6196. function SetAgent($s_agent)
  6197. {
  6198. $this->_sAgent = $s_agent;
  6199. }
  6200. };
  6201. //
  6202. // Load a template file into a string.
  6203. //
  6204. function LoadTemplate($s_name,$s_dir,$s_url,$b_ret_lines = false)
  6205. {
  6206. global $php_errormsg;
  6207. $s_buf = "";
  6208. $a_lines = array();
  6209. if (!empty($s_dir))
  6210. {
  6211. $s_name = "$s_dir/".basename($s_name);
  6212. @ $fp = fopen($s_name,"r");
  6213. if ($fp === false)
  6214. {
  6215. SendAlert(GetMessage(MSG_OPEN_TEMPLATE,array("NAME"=>$s_name,
  6216. "ERROR"=>CheckString($php_errormsg))));
  6217. return (false);
  6218. }
  6219. if ($b_ret_lines)
  6220. $a_lines = ReadLines($fp);
  6221. else
  6222. //
  6223. // load the whole template into a string
  6224. //
  6225. $s_buf = fread($fp,filesize($s_name));
  6226. fclose($fp);
  6227. }
  6228. else
  6229. {
  6230. if (substr($s_url,-1) == '/')
  6231. $s_name = "$s_url".basename($s_name);
  6232. else
  6233. $s_name = "$s_url/".basename($s_name);
  6234. if (($m_data = GetURL($s_name,$s_error,$b_ret_lines)) === false)
  6235. {
  6236. SendAlert($s_error);
  6237. return (false);
  6238. }
  6239. if ($b_ret_lines)
  6240. {
  6241. $a_lines = $m_data;
  6242. //
  6243. // strip line terminations from each line
  6244. //
  6245. for ($ii = count($a_lines) ; --$ii >= 0 ; )
  6246. {
  6247. $s_line = $a_lines[$ii];
  6248. $s_line = str_replace("\r","",$s_line);
  6249. $s_line = str_replace("\n","",$s_line);
  6250. $a_lines[$ii] = $s_line;
  6251. }
  6252. }
  6253. else
  6254. $s_buf = $m_data;
  6255. }
  6256. return ($b_ret_lines ? $a_lines : $s_buf);
  6257. }
  6258. //
  6259. // To show an error template. The template must be HTML and, for security
  6260. // reasons, must be a file on the server in the directory specified
  6261. // by $TEMPLATEDIR or $TEMPLATEURL.
  6262. // $a_specs is an array of substitutions to perform, as follows:
  6263. // tag-name replacement string
  6264. //
  6265. // For example:
  6266. // "fmerror"=>"An error message"
  6267. //
  6268. function ShowErrorTemplate($s_name,$a_specs,$b_user_error)
  6269. {
  6270. global $TEMPLATEURL,$TEMPLATEDIR;
  6271. if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
  6272. {
  6273. SendAlert(GetMessage(MSG_TEMPLATES));
  6274. return (false);
  6275. }
  6276. if (($s_buf = LoadTemplate($s_name,$TEMPLATEDIR,$TEMPLATEURL)) === false)
  6277. return (false);
  6278. //
  6279. // now look for the tags to replace
  6280. //
  6281. foreach ($a_specs as $s_tag=>$s_value)
  6282. //
  6283. // search for
  6284. // <tagname/>
  6285. // or
  6286. // [tagname/]
  6287. // with optional whitespace
  6288. //
  6289. $s_buf = preg_replace('/[<\[]\s*'.preg_quote($s_tag,"/").'\s*\/\s*[>\]]/ims',
  6290. nl2br($s_value),$s_buf);
  6291. if ($b_user_error)
  6292. {
  6293. // strip any <fmusererror> and </fmusererror> tags
  6294. // or [fmusererrors] and [/fmusererror] tags
  6295. //
  6296. // You can show information that's specific to user
  6297. // errors between these special tags.
  6298. //
  6299. $s_buf = preg_replace('/[<\[]\s*\/?\s*fmusererror\s*[>\]]/ims','',$s_buf);
  6300. //
  6301. // since this isn't a system error, strip anything between
  6302. // <fmsyserror> and </fmsyserror>
  6303. // or [fmsyserrors] and [/fmsyserror] tags
  6304. //
  6305. $s_buf = preg_replace('/[<\[]\s*fmsyserror\s*[>\]].*[<\[]\s*\/\s*fmsyserror\s*[>\]]/ims','',$s_buf);
  6306. }
  6307. else
  6308. {
  6309. // strip any <fmsyserror> and </fmsyserror> tags
  6310. // or [fmsyserrors] and [/fmsyserror] tags
  6311. //
  6312. // You can show information that's specific to system
  6313. // errors between these special tags.
  6314. //
  6315. $s_buf = preg_replace('/[<\[]\s*\/?\s*fmsyserror\s*[>\]]/ims','',$s_buf);
  6316. //
  6317. // since this isn't a user error, strip anything between
  6318. // <fmusererror> and </fmusererror>
  6319. // or [fmusererrors] and [/fmusererror] tags
  6320. //
  6321. $s_buf = preg_replace('/[<\[]\s*fmusererror\s*[>\]].*[<\[]\s*\/\s*fmusererror\s*[>\]]/ims','',$s_buf);
  6322. }
  6323. //
  6324. // just output the page
  6325. //
  6326. echo $s_buf;
  6327. return (true);
  6328. }
  6329. //
  6330. // To show an error to the user.
  6331. //
  6332. function ShowError($error_code,$error_mesg,$b_user_error,
  6333. $b_alerted = false,$a_item_list = array(),$s_extra_info = "")
  6334. {
  6335. global $SPECIAL_FIELDS,$SPECIAL_MULTI,$SPECIAL_VALUES;
  6336. global $aServerVars,$aStrippedFormVars;
  6337. //
  6338. // Testing with PHP 4.0.6 indicates that sessions don't always work.
  6339. // So, we'll also add the error to the URL, unless
  6340. // PUT_DATA_IN_URL is false.
  6341. //
  6342. SetSession("FormError",$error_mesg);
  6343. SetSession("FormErrorInfo",$s_extra_info);
  6344. SetSession("FormErrorCode",$error_code);
  6345. SetSession("FormErrorItems",$a_item_list);
  6346. SetSession("FormIsUserError",$b_user_error);
  6347. SetSession("FormAlerted",$b_alerted);
  6348. SetSession("FormData",array());
  6349. $bad_url = $SPECIAL_VALUES["bad_url"];
  6350. $bad_template = $SPECIAL_VALUES["bad_template"];
  6351. $this_form = $SPECIAL_VALUES["this_form"];
  6352. if (IsAjax())
  6353. {
  6354. JSON_Result("ERROR",array("ErrorCode"=>$error_code,
  6355. "UserError"=>$b_user_error,
  6356. "ErrorMesg"=>$error_mesg,
  6357. "Alerted"=>$b_alerted,
  6358. "ErrorItems"=>$a_item_list));
  6359. ZapSession();
  6360. }
  6361. elseif (!empty($bad_url))
  6362. {
  6363. $a_params = array();
  6364. if (PUT_DATA_IN_URL)
  6365. {
  6366. $a_params[] = "this_form=".urlencode("$this_form");
  6367. $a_params[] = "bad_template=".urlencode("$bad_template");
  6368. $a_params[] = "error=".urlencode("$error_mesg");
  6369. $a_params[] = "extra=".urlencode("$s_extra_info");
  6370. $a_params[] = "errcode=".urlencode("$error_code");
  6371. $a_params[] = "isusererror=".($b_user_error ? "1" : "0");
  6372. $a_params[] = "alerted=".($b_alerted ? "1" : "0");
  6373. $i_count = 1;
  6374. foreach ($a_item_list as $s_item)
  6375. {
  6376. $a_params[] = "erroritem$i_count=".urlencode("$s_item");
  6377. $i_count++;
  6378. }
  6379. }
  6380. else
  6381. {
  6382. $a_sess_data = GetSession("FormData");
  6383. $a_sess_data["this_form"] = "$this_form";
  6384. $a_sess_data["bad_template"] = "$bad_template";
  6385. SetSession("FormData",$a_sess_data);
  6386. //
  6387. // tell the bad_url to look in the session only
  6388. //
  6389. $a_params[] = "insession=1";
  6390. }
  6391. //
  6392. // Add the posted data to the URL so that an intelligent
  6393. // $bad_url can call the form again
  6394. //
  6395. foreach ($aStrippedFormVars as $s_name=>$m_value)
  6396. {
  6397. //
  6398. // skip special fields
  6399. //
  6400. $b_special = false;
  6401. if (in_array($s_name,$SPECIAL_FIELDS))
  6402. $b_special = true;
  6403. else
  6404. {
  6405. foreach ($SPECIAL_MULTI as $s_multi_fld)
  6406. {
  6407. $i_len = strlen($s_multi_fld);
  6408. if (substr($s_name,0,$i_len) == $s_multi_fld)
  6409. {
  6410. $i_index = (int) substr($s_name,$i_len);
  6411. if ($i_index > 0)
  6412. {
  6413. $b_special = true;
  6414. break;
  6415. }
  6416. }
  6417. }
  6418. }
  6419. if (!$b_special)
  6420. {
  6421. if (PUT_DATA_IN_URL)
  6422. {
  6423. if (is_array($m_value))
  6424. foreach ($m_value as $s_value)
  6425. $a_params[] = "$s_name".'[]='.
  6426. urlencode(substr($s_value,0,MAXSTRING));
  6427. else
  6428. $a_params[] = "$s_name=".urlencode(substr($m_value,0,MAXSTRING));
  6429. }
  6430. else
  6431. {
  6432. $a_sess_data = GetSession("FormData");
  6433. if (is_array($m_value))
  6434. $a_sess_data["$s_name"] = $m_value;
  6435. else
  6436. $a_sess_data["$s_name"] = substr($m_value,0,MAXSTRING);
  6437. SetSession("FormData",$a_sess_data);
  6438. }
  6439. }
  6440. }
  6441. //
  6442. // Now add the authentication data, if any
  6443. //
  6444. if ((isset($aServerVars["PHP_AUTH_USER"]) &&
  6445. $aServerVars["PHP_AUTH_USER"] !== "") ||
  6446. (isset($aServerVars["PHP_AUTH_PW"]) &&
  6447. $aServerVars["PHP_AUTH_PW"] !== ""))
  6448. {
  6449. if (PUT_DATA_IN_URL)
  6450. {
  6451. if (isset($aServerVars["PHP_AUTH_USER"]))
  6452. $a_params[] = "PHP_AUTH_USER=".urlencode($aServerVars["PHP_AUTH_USER"]);
  6453. if (isset($aServerVars["PHP_AUTH_PW"]))
  6454. $a_params[] = "PHP_AUTH_PW=".urlencode($aServerVars["PHP_AUTH_PW"]);
  6455. if (isset($aServerVars["PHP_AUTH_TYPE"]))
  6456. $a_params[] = "PHP_AUTH_TYPE=".urlencode($aServerVars["PHP_AUTH_TYPE"]);
  6457. }
  6458. else
  6459. {
  6460. $a_sess_data = GetSession("FormData");
  6461. if (isset($aServerVars["PHP_AUTH_USER"]))
  6462. $a_sess_data["PHP_AUTH_USER"] = $aServerVars["PHP_AUTH_USER"];
  6463. if (isset($aServerVars["PHP_AUTH_PW"]))
  6464. $a_sess_data["PHP_AUTH_PW"] = $aServerVars["PHP_AUTH_PW"];
  6465. if (isset($aServerVars["PHP_AUTH_TYPE"]))
  6466. $a_sess_data["PHP_AUTH_TYPE"] = $aServerVars["PHP_AUTH_TYPE"];
  6467. SetSession("FormData",$a_sess_data);
  6468. }
  6469. }
  6470. $bad_url = AddURLParams($bad_url,$a_params,false);
  6471. Redirect($bad_url,GetMessage(MSG_FORM_ERROR));
  6472. }
  6473. else
  6474. {
  6475. if (!empty($bad_template))
  6476. {
  6477. $a_specs = array("fmerror"=>htmlspecialchars("$error_mesg"),
  6478. "fmerrorcode"=>htmlspecialchars("$error_code"),
  6479. "fmfullerror"=>htmlspecialchars("$error_mesg")."\n".
  6480. htmlspecialchars("$s_extra_info"),
  6481. "fmerrorextra"=>htmlspecialchars("$s_extra_info"),);
  6482. for ($i_count = 1 ; $i_count <= 20 ; $i_count++)
  6483. $a_specs["fmerroritem$i_count"] = "";
  6484. $i_count = 1;
  6485. foreach ($a_item_list as $s_item)
  6486. {
  6487. $a_specs["fmerroritem$i_count"] = htmlspecialchars($s_item);
  6488. $i_count++;
  6489. }
  6490. $s_list = "";
  6491. foreach ($a_item_list as $s_item)
  6492. $s_list .= "<li>".htmlspecialchars($s_item)."</li>";
  6493. $a_specs["fmerroritemlist"] = $s_list;
  6494. if (ShowErrorTemplate($bad_template,$a_specs,$b_user_error))
  6495. return;
  6496. }
  6497. $s_text = GetMessage(MSG_ERROR_PROC);
  6498. if ($b_user_error)
  6499. $s_text .= $error_mesg."\n".FixedHTMLEntities($s_extra_info);
  6500. else
  6501. {
  6502. global $SERVER;
  6503. if ($b_alerted)
  6504. $s_text .= GetMessage(MSG_ALERT_DONE,array("SERVER"=>$SERVER));
  6505. else
  6506. $s_text .= GetMessage(MSG_PLS_CONTACT,array("SERVER"=>$SERVER));
  6507. $s_text .= GetMessage(MSG_APOLOGY,array("SERVER"=>$SERVER));
  6508. }
  6509. CreatePage($s_text,GetMessage(MSG_FORM_ERROR),false);
  6510. //
  6511. // the session data is not needed now
  6512. //
  6513. ZapSession();
  6514. }
  6515. }
  6516. //
  6517. // Report an error. Same as Error, but implements
  6518. // ATTACK_DETECTION_IGNORE_ERRORS.
  6519. //
  6520. function ErrorWithIgnore($error_code,$error_mesg,$b_filter = true,$show = true,$int_mesg = "")
  6521. {
  6522. if (function_exists('FMHookErrorWithIgnore'))
  6523. FMHookErrorWithIgnore($error_code,$error_mesg,$b_filter,$show,$int_mesg);
  6524. $b_alerted = false;
  6525. if (!ATTACK_DETECTION_IGNORE_ERRORS)
  6526. if (SendAlert("$error_code\n *****$int_mesg*****\nError=$error_mesg\n",$b_filter))
  6527. $b_alerted = true;
  6528. if ($show)
  6529. ShowError($error_code,$error_mesg,false,$b_alerted);
  6530. else
  6531. //
  6532. // show something to the user
  6533. //
  6534. ShowError($error_code,GetMessage(MSG_SUBM_FAILED),false,$b_alerted);
  6535. exit;
  6536. }
  6537. //
  6538. // Report an error
  6539. //
  6540. function Error($error_code,$error_mesg,$b_filter = true,$show = true,$int_mesg = "")
  6541. {
  6542. if (function_exists('FMHookError'))
  6543. FMHookError($error_code,$error_mesg,$b_filter,$show,$int_mesg);
  6544. $b_alerted = false;
  6545. if (SendAlert("$error_code\n *****$int_mesg*****\nError=$error_mesg\n",$b_filter))
  6546. $b_alerted = true;
  6547. if ($show)
  6548. ShowError($error_code,$error_mesg,false,$b_alerted);
  6549. else
  6550. //
  6551. // show something to the user
  6552. //
  6553. ShowError($error_code,GetMessage(MSG_SUBM_FAILED),false,$b_alerted);
  6554. exit;
  6555. }
  6556. //
  6557. // Report a user error
  6558. //
  6559. function UserError($s_error_code,$s_error_mesg,
  6560. $s_extra_info = "",$a_item_list = array())
  6561. {
  6562. if (function_exists('FMHookUserError'))
  6563. FMHookUserError($s_error_code,$s_error_mesg,$s_extra_info,$a_item_list);
  6564. $b_alerted = false;
  6565. if (ALERT_ON_USER_ERROR &&
  6566. SendAlert("$s_error_code\nError=$s_error_mesg\n$s_extra_info\n"))
  6567. $b_alerted = true;
  6568. ShowError($s_error_code,$s_error_mesg,true,$b_alerted,$a_item_list,$s_extra_info);
  6569. exit;
  6570. }
  6571. //
  6572. // Create a simple page with the given text.
  6573. //
  6574. function CreatePage($text,$title = "",$b_show_about = true)
  6575. {
  6576. global $FM_VERS,$sHTMLCharSet;
  6577. if (IsAjax())
  6578. {
  6579. //
  6580. // CreatePage should not be called in Ajax mode.
  6581. // If it is, it must be an error or debugging state.
  6582. //
  6583. JSON_Result("ERROR",array("ErrorCode"=>$title,
  6584. "ErrorMesg"=>$text));
  6585. }
  6586. else
  6587. {
  6588. echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
  6589. echo '<html xmlns="http://www.w3.org/1999/xhtml">'."\n";
  6590. echo "<head>\n";
  6591. if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  6592. echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$sHTMLCharSet\" />\n";
  6593. if ($title != "")
  6594. echo "<title>".FixedHTMLEntities($title)."</title>\n";
  6595. echo "</head>\n";
  6596. echo "<body>\n";
  6597. echo nl2br($text);
  6598. echo "<p />";
  6599. if ($b_show_about)
  6600. {
  6601. echo "<p><small>\n";
  6602. echo GetMessage(MSG_ABOUT_FORMMAIL,array("FM_VERS"=>$FM_VERS,
  6603. "TECTITE"=>"www.tectite.com"));
  6604. echo "</small></p>\n";
  6605. }
  6606. echo "</body>\n";
  6607. echo "</html>\n";
  6608. }
  6609. }
  6610. //
  6611. // Strip slashes if magic_quotes_gpc is set.
  6612. //
  6613. function StripGPC($s_value)
  6614. {
  6615. if (get_magic_quotes_gpc() != 0)
  6616. $s_value = stripslashes($s_value);
  6617. return ($s_value);
  6618. }
  6619. //
  6620. // return an array, stripped of slashes if magic_quotes_gpc is set
  6621. //
  6622. function StripGPCArray($a_values)
  6623. {
  6624. if (get_magic_quotes_gpc() != 0)
  6625. foreach ($a_values as $m_key=>$m_value)
  6626. if (is_array($m_value))
  6627. //
  6628. // strip arrays recursively
  6629. //
  6630. $a_values[$m_key] = StripGPCArray($m_value);
  6631. else
  6632. //
  6633. // convert scalar to string and strip
  6634. //
  6635. $a_values[$m_key] = stripslashes("$m_value");
  6636. return ($a_values);
  6637. }
  6638. //
  6639. // Strip a value of unwanted characters, which might be hacks.
  6640. // The stripping of \r and \n is a *critical* security feature.
  6641. //
  6642. function Strip($value)
  6643. {
  6644. //
  6645. // When working with character sets such as UTF-8, stripping
  6646. // control characters is a *really bad idea* and breaks things.
  6647. // From version 8.22, FormMail only strips \r and \n as these
  6648. // are really the only characters that can cause header hacks
  6649. // to be inserted. (Strip means replace with a single space).
  6650. // We also handle multiple spaces.
  6651. //
  6652. $value = preg_replace('/[ \r\n]+/'," ",$value); // zap all CRLF and multiple blanks
  6653. return ($value);
  6654. }
  6655. //
  6656. // Clean a value. This means:
  6657. // 1. convert to string
  6658. // 2. truncate to maximum length
  6659. // 3. strip the value of unwanted or dangerous characters (hacks)
  6660. // 4. trim both ends of whitespace
  6661. // Each element of an array is cleaned as above. This process occurs
  6662. // recursively, so arrays of arrays work OK too (though there's no
  6663. // need for that in this program).
  6664. //
  6665. // Non-scalar values are changed to the string "<X>" where X is the type.
  6666. // In general, FormMail won't receive non-scalar non-array values, so this
  6667. // is more a future-proofing measure.
  6668. //
  6669. function CleanValue($m_value)
  6670. {
  6671. if (is_array($m_value))
  6672. {
  6673. foreach ($m_value as $m_key=>$m_item)
  6674. $m_value[$m_key] = CleanValue($m_item);
  6675. }
  6676. elseif (!is_scalar($m_value))
  6677. $m_value = "<".gettype($m_value).">";
  6678. else
  6679. {
  6680. //
  6681. // convert to string and truncate
  6682. //
  6683. $m_value = substr("$m_value",0,MAXSTRING);
  6684. //
  6685. // strip unwanted chars and trim
  6686. //
  6687. $m_value = trim(Strip($m_value));
  6688. }
  6689. return ($m_value);
  6690. }
  6691. //
  6692. // Clean a special value. Special values listed in $SPECIAL_NOSTRIP
  6693. // will not be cleaned.
  6694. //
  6695. function SpecialCleanValue($s_name,$m_value)
  6696. {
  6697. global $SPECIAL_NOSTRIP;
  6698. if (!in_array($s_name,$SPECIAL_NOSTRIP))
  6699. $m_value = CleanValue($m_value);
  6700. return ($m_value);
  6701. }
  6702. //
  6703. // Return the fields and their values in a string containing one
  6704. // field per line.
  6705. //
  6706. function MakeFieldOutput($a_order,$a_fields,$s_line_feed = BODY_LF)
  6707. {
  6708. $n_order = count($a_order);
  6709. $s_output = "";
  6710. for ($ii = 0 ; $ii < $n_order ; $ii++)
  6711. {
  6712. $s_name = $a_order[$ii];
  6713. if (isset($a_fields[$s_name]))
  6714. $s_output .= "$s_name: ".$a_fields[$s_name].$s_line_feed;
  6715. }
  6716. return ($s_output);
  6717. }
  6718. //
  6719. // Check if a field name is special. Returns true if it is.
  6720. //
  6721. function IsSpecialField($s_name)
  6722. {
  6723. global $SPECIAL_FIELDS;
  6724. return (in_array($s_name,$SPECIAL_FIELDS));
  6725. }
  6726. //
  6727. // Set a special field value.
  6728. //
  6729. function SetSpecialField($s_name,$m_value)
  6730. {
  6731. global $SPECIAL_VALUES;
  6732. //
  6733. // most special values cannot be arrays; ignore them if they are
  6734. //
  6735. if (is_array($m_value))
  6736. {
  6737. global $SPECIAL_ARRAYS;
  6738. if (!in_array($s_name,$SPECIAL_ARRAYS))
  6739. return;
  6740. }
  6741. $SPECIAL_VALUES[$s_name] = SpecialCleanValue($s_name,$m_value);
  6742. }
  6743. //
  6744. // Check if a field name is a special "multi" field.
  6745. // A multi field is the name plus a sequence number. For example,
  6746. // conditions1
  6747. // conditions2
  6748. // Returns a list (array) if it is, otherwise false if not.
  6749. // The list contains:
  6750. // 1. the name of the special multi field
  6751. // 2. the index number for multi field
  6752. //
  6753. function IsSpecialMultiField($s_name)
  6754. {
  6755. global $SPECIAL_MULTI;
  6756. foreach ($SPECIAL_MULTI as $s_multi_fld)
  6757. {
  6758. $i_len = strlen($s_multi_fld);
  6759. //
  6760. // look for nameN where N is a number starting from 1
  6761. //
  6762. if (substr($s_name,0,$i_len) == $s_multi_fld)
  6763. {
  6764. $i_index = (int) substr($s_name,$i_len);
  6765. if ($i_index > 0)
  6766. {
  6767. //
  6768. // re-index to zero
  6769. //
  6770. --$i_index;
  6771. return (array($s_multi_fld,$i_index));
  6772. }
  6773. }
  6774. }
  6775. return (false);
  6776. }
  6777. //
  6778. // Set a multi field value.
  6779. //
  6780. function SetSpecialMultiField($s_name,$i_index,$m_value)
  6781. {
  6782. global $SPECIAL_VALUES;
  6783. //
  6784. // these special fields cannot be arrays - ignore if it is
  6785. //
  6786. if (!is_array($m_value))
  6787. $SPECIAL_VALUES[$s_name][$i_index] = SpecialCleanValue($s_name,$m_value);
  6788. }
  6789. //
  6790. // Check if a field is part of Reverse Captcha processing.
  6791. //
  6792. function IsReverseCaptchaField($s_name)
  6793. {
  6794. global $ATTACK_DETECTION_REVERSE_CAPTCHA;
  6795. return (isset($ATTACK_DETECTION_REVERSE_CAPTCHA[$s_name]));
  6796. }
  6797. //
  6798. // Process a field
  6799. //
  6800. function ProcessField($s_name,$raw_value,&$a_order,&$a_fields,&$a_raw_fields)
  6801. {
  6802. global $FORMATTED_INPUT;
  6803. //
  6804. // fields go into an array of special values or an array of other values
  6805. // or get completely ignored.
  6806. //
  6807. $b_ignore = $b_special = false;
  6808. if (IsSpecialField($s_name))
  6809. {
  6810. SetSpecialField($s_name,$raw_value);
  6811. $b_special = true;
  6812. }
  6813. //
  6814. // check for multiple valued special fields
  6815. //
  6816. if (($a_multi_fld = IsSpecialMultiField($s_name)) !== false)
  6817. {
  6818. SetSpecialMultiField($a_multi_fld[0],$a_multi_fld[1],$raw_value);
  6819. $b_special = true;
  6820. }
  6821. if (!$b_special)
  6822. {
  6823. if (IsReverseCaptchaField($s_name))
  6824. $b_ignore = true;
  6825. }
  6826. if (!$b_special && !$b_ignore)
  6827. {
  6828. //
  6829. // return the raw value unchanged in the $a_raw_fields array
  6830. //
  6831. $a_raw_fields[$s_name] = $raw_value;
  6832. //
  6833. // handle checkboxes and multiple-selection lists
  6834. // Thanks go to Theodore Boardman for the suggestion
  6835. // and initial working code.
  6836. //
  6837. if (is_array($raw_value))
  6838. {
  6839. if (empty($raw_value))
  6840. $s_cleaned_value = "";
  6841. else
  6842. {
  6843. $a_cleaned_values = CleanValue($raw_value);
  6844. //
  6845. // the output is a comma separated list of values for the
  6846. // checkbox. For example,
  6847. // events: Diving,Cycling,Running
  6848. //
  6849. // Set the clean value to the list of cleaned checkbox
  6850. // values.
  6851. // First, remove any commas in the values themselves.
  6852. //
  6853. $a_cleaned_values = str_replace(",","",$a_cleaned_values);
  6854. $s_cleaned_value = implode(",",$a_cleaned_values);
  6855. }
  6856. }
  6857. else
  6858. {
  6859. //
  6860. // NOTE: there is a minor bug here now that we support
  6861. // $FORM_INI_FILE. The INI file is processed at the end
  6862. // so if you set the mail_options below in the INI file they
  6863. // won't get processed here. This means you must set
  6864. // the following mail_options in the HTML form for now.
  6865. // (To be fixed at a later date. RJR 17-Feb-06).
  6866. //
  6867. //
  6868. // if the form specifies the "KeepLines" option,
  6869. // don't strip new lines
  6870. //
  6871. if (IsMailOptionSet("KeepLines") && strpos($raw_value,"\n") !== false)
  6872. {
  6873. //
  6874. // truncate first
  6875. //
  6876. $s_truncated = substr("$raw_value",0,MAXSTRING);
  6877. //
  6878. // split into lines, clean each individual line,
  6879. // then put it back together again
  6880. //
  6881. $a_lines = explode("\n",$s_truncated);
  6882. $a_lines = CleanValue($a_lines);
  6883. $s_cleaned_value = implode(BODY_LF,$a_lines);
  6884. //
  6885. // and, for this special case, prepend a new line
  6886. // so that the value is shown on a fresh line
  6887. //
  6888. $s_cleaned_value = BODY_LF.$s_cleaned_value;
  6889. }
  6890. else
  6891. $s_cleaned_value = CleanValue($raw_value);
  6892. }
  6893. //
  6894. // if the form specifies the "NoEmpty" option, skip
  6895. // empty values.
  6896. //
  6897. if (!IsMailOptionSet("NoEmpty") || !FieldManager::IsEmpty($s_cleaned_value))
  6898. if (!IsMailExcluded($s_name))
  6899. {
  6900. //
  6901. // by default, we maintain the order as passed in
  6902. // the HTTP request
  6903. //
  6904. $a_order[] = $s_name;
  6905. $a_fields[$s_name] = $s_cleaned_value;
  6906. }
  6907. //
  6908. // add to the $FORMATTED_INPUT array for debugging and
  6909. // error reporting
  6910. //
  6911. array_push($FORMATTED_INPUT,"$s_name: '$s_cleaned_value'");
  6912. }
  6913. }
  6914. //
  6915. // Parse the input variables and return:
  6916. // 1. an array that specifies the required field order in the output
  6917. // 2. an array containing the non-special cleaned field values indexed
  6918. // by field name.
  6919. // 3. an array containing the non-special raw field values indexed by
  6920. // field name.
  6921. //
  6922. function ParseInput($a_vars)
  6923. {
  6924. $a_order = array();
  6925. $a_fields = array();
  6926. $a_raw_fields = array();
  6927. //
  6928. // scan the array of values passed in (name-value pairs) and
  6929. // produce slightly formatted (not HTML) textual output
  6930. // and extract any special values found.
  6931. //
  6932. foreach ($a_vars as $s_name=>$raw_value)
  6933. ProcessField($s_name,$raw_value,$a_order,$a_fields,$a_raw_fields);
  6934. return (array($a_order,$a_fields,$a_raw_fields));
  6935. }
  6936. //
  6937. // Get the URL for sending to the CRM.
  6938. //
  6939. function GetCRMURL($spec,$vars,$url)
  6940. {
  6941. $bad = false;
  6942. $list = TrimArray(explode(",",$spec));
  6943. $map = array();
  6944. for ($ii = 0 ; $ii < count($list) ; $ii++)
  6945. {
  6946. $name = $list[$ii];
  6947. if ($name)
  6948. {
  6949. //
  6950. // the specification must be in this format:
  6951. // form-field-name:CRM-field-name
  6952. //
  6953. if (($i_crm_name_pos = strpos($name,":")) > 0)
  6954. {
  6955. $s_crm_name = substr($name,$i_crm_name_pos + 1);
  6956. $name = substr($name,0,$i_crm_name_pos);
  6957. if (isset($vars[$name]))
  6958. {
  6959. $map[] = $s_crm_name."=".urlencode($vars[$name]);
  6960. $map[] = "Orig_".$s_crm_name."=".urlencode($name);
  6961. }
  6962. }
  6963. else
  6964. {
  6965. //
  6966. // not the right format, so just include as a parameter
  6967. // check for name=value format to choose encoding
  6968. //
  6969. $a_values = explode("=",$name);
  6970. if (count($a_values) > 1)
  6971. $map[] = urlencode($a_values[0])."=".urlencode($a_values[1]);
  6972. else
  6973. $map[] = urlencode($a_values[0]);
  6974. }
  6975. }
  6976. }
  6977. if (count($map) == 0)
  6978. return ("");
  6979. return (AddURLParams($url,$map,false));
  6980. }
  6981. //
  6982. // strip the HTML from a string or array of strings
  6983. //
  6984. function StripHTML($m_value,$s_line_feed = "\n")
  6985. {
  6986. if (is_array($m_value))
  6987. {
  6988. foreach ($m_value as $m_key=>$s_str)
  6989. $m_value[$m_key] = StripHTML($s_str);
  6990. return ($m_value);
  6991. }
  6992. $s_str = $m_value;
  6993. //
  6994. // strip HTML comments (s option means include new lines in matches)
  6995. //
  6996. $s_str = preg_replace('/<!--([^-]*([^-]|-([^-]|-[^>])))*-->/s','',$s_str);
  6997. //
  6998. // strip any scripts (i option means case-insensitive)
  6999. //
  7000. $s_str = preg_replace('/<script[^>]*?>.*?<\/script[^>]*?>/si','',$s_str);
  7001. //
  7002. // replace paragraphs with new lines (line feeds)
  7003. //
  7004. $s_str = preg_replace('/<p[^>]*?>/i',$s_line_feed,$s_str);
  7005. //
  7006. // replace breaks with new lines (line feeds)
  7007. //
  7008. $s_str = preg_replace('/<br[[:space:]]*\/?[[:space:]]*>/i',$s_line_feed,$s_str);
  7009. //
  7010. // overcome this bug: http://bugs.php.net/bug.php?id=21311
  7011. //
  7012. $s_str = preg_replace('/<![^>]*>/s','',$s_str);
  7013. //
  7014. // get rid of all HTML tags
  7015. //
  7016. $s_str = strip_tags($s_str);
  7017. return ($s_str);
  7018. }
  7019. //
  7020. // Check for valid URL in TARGET_URLS
  7021. //
  7022. function CheckValidURL($s_url)
  7023. {
  7024. global $TARGET_URLS;
  7025. foreach ($TARGET_URLS as $s_prefix)
  7026. if (!empty($s_prefix) &&
  7027. strtolower(substr($s_url,0,strlen($s_prefix))) ==
  7028. strtolower($s_prefix))
  7029. return (true);
  7030. return (false);
  7031. }
  7032. //
  7033. // Scan the given data for fields returned from the CRM.
  7034. // A field has this following format:
  7035. // __FIELDNAME__=value
  7036. // terminated by a line feed.
  7037. //
  7038. function FindCRMFields($s_data)
  7039. {
  7040. $a_ret = array();
  7041. if (preg_match_all('/^__([A-Za-z][A-Za-z0-9_]*)__=(.*)$/m',$s_data,$a_matches) === false)
  7042. SendAlert(GetMessage(MSG_PREG_FAILED));
  7043. else
  7044. {
  7045. $n_matches = count($a_matches[0]);
  7046. // SendAlert("$n_matches on '$s_data'");
  7047. for ($ii = 0 ; $ii < $n_matches ; $ii++)
  7048. if (isset($a_matches[1][$ii]) && isset($a_matches[2][$ii]))
  7049. $a_ret[$a_matches[1][$ii]] = $a_matches[2][$ii];
  7050. }
  7051. return ($a_ret);
  7052. }
  7053. //
  7054. // open the given URL to send data to it, we expect the response
  7055. // to contain at least '__OK__=' followed by true or false
  7056. //
  7057. function SendToCRM($s_url,&$a_data)
  7058. {
  7059. global $php_errormsg;
  7060. if (!CheckValidURL($s_url))
  7061. {
  7062. SendAlert(GetMessage(MSG_URL_INVALID,array("URL"=>$s_url)));
  7063. return (false);
  7064. }
  7065. @ $fp = fopen($s_url,"r"); // RJR: TO DO: re-implement using NetIO
  7066. if ($fp === false)
  7067. {
  7068. SendAlert(GetMessage(MSG_URL_OPEN,array("URL"=>$s_url,
  7069. "ERROR"=>CheckString($php_errormsg))));
  7070. return (false);
  7071. }
  7072. $s_mesg = "";
  7073. while (!feof($fp))
  7074. {
  7075. $s_line = fgets($fp,4096);
  7076. $s_mesg .= $s_line;
  7077. }
  7078. fclose($fp);
  7079. $s_mesg = StripHTML($s_mesg);
  7080. $s_result = preg_match('/__OK__=(.*)/',$s_mesg,$a_matches);
  7081. if (count($a_matches) < 2 || $a_matches[1] === "")
  7082. {
  7083. //
  7084. // no agreed __OK__ value returned - assume system error
  7085. //
  7086. SendAlert(GetMessage(MSG_CRM_FAILED,array("URL"=>$s_url,
  7087. "MSG"=>$s_mesg)));
  7088. return (false);
  7089. }
  7090. //
  7091. // look for fields to return
  7092. //
  7093. $a_data = FindCRMFields($s_mesg);
  7094. //
  7095. // check for success or user error
  7096. //
  7097. switch (strtolower($a_matches[1]))
  7098. {
  7099. case "true":
  7100. break;
  7101. case "false":
  7102. //
  7103. // check for user error
  7104. //
  7105. if (isset($a_data["USERERRORCODE"]))
  7106. {
  7107. $s_error_code = "crm_error";
  7108. $s_error_mesg = GetMessage(MSG_CRM_FORM_ERROR);
  7109. $s_error_code .= $a_data["USERERRORCODE"];
  7110. if (isset($a_data["USERERRORMESG"]))
  7111. $s_error_mesg = $a_data["USERERRORMESG"];
  7112. UserError($s_error_code,$s_error_mesg);
  7113. // no return
  7114. }
  7115. return (false);
  7116. }
  7117. return (true);
  7118. }
  7119. //
  7120. // Split into field name and friendly name; returns an array with
  7121. // two elements.
  7122. // Format is:
  7123. // fieldname:Nice printable name for displaying
  7124. //
  7125. function GetFriendlyName($s_name)
  7126. {
  7127. if (($i_pos = strpos($s_name,':')) === false)
  7128. return (array(trim($s_name),trim($s_name)));
  7129. return (array(trim(substr($s_name,0,$i_pos)),trim(substr($s_name,$i_pos+1))));
  7130. }
  7131. define("REQUIREDOPS","|^!="); // operand characters for advanced required processing
  7132. //
  7133. // Perform a field comparison test.
  7134. //
  7135. function FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,&$s_error_mesg,
  7136. $s_friendly1 = "",$s_friendly2 = "")
  7137. {
  7138. $b_ok = true;
  7139. //
  7140. // perform the test
  7141. //
  7142. switch ($s_oper)
  7143. {
  7144. case '&': // both fields must be present
  7145. if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) &&
  7146. !TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
  7147. ; // OK
  7148. else
  7149. {
  7150. //
  7151. // failed
  7152. //
  7153. $s_error_mesg = GetMessage(MSG_AND,array("ITEM1"=>$s_friendly1,
  7154. "ITEM2"=>$s_friendly2));
  7155. $b_ok = false;
  7156. }
  7157. break;
  7158. case '|': // either field or both must be present
  7159. if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) ||
  7160. !TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
  7161. ; // OK
  7162. else
  7163. {
  7164. //
  7165. // failed
  7166. //
  7167. $s_error_mesg = GetMessage(MSG_OR,array("ITEM1"=>$s_friendly1,
  7168. "ITEM2"=>$s_friendly2));
  7169. $b_ok = false;
  7170. }
  7171. break;
  7172. case '^': // either field but not both must be present
  7173. $b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
  7174. $b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
  7175. if ($b_got1 || $b_got2)
  7176. {
  7177. if ($b_got1 && $b_got2)
  7178. {
  7179. //
  7180. // failed
  7181. //
  7182. $s_error_mesg = GetMessage(MSG_NOT_BOTH,
  7183. array("ITEM1"=>$s_friendly1,
  7184. "ITEM2"=>$s_friendly2));
  7185. $b_ok = false;
  7186. }
  7187. }
  7188. else
  7189. {
  7190. //
  7191. // failed
  7192. //
  7193. $s_error_mesg = GetMessage(MSG_XOR,
  7194. array("ITEM1"=>$s_friendly1,
  7195. "ITEM2"=>$s_friendly2));
  7196. $b_ok = false;
  7197. }
  7198. break;
  7199. case '!=':
  7200. case '=':
  7201. $b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
  7202. $b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
  7203. if ($b_got1 && $b_got2)
  7204. $b_match = (GetFieldValue($s_fld1,$a_vars) ==
  7205. GetFieldValue($s_fld2,$a_vars));
  7206. elseif (!$b_got1 && !$b_got2)
  7207. //
  7208. // haven't got either value - they match
  7209. //
  7210. $b_match = true;
  7211. else
  7212. //
  7213. // got one value, but not the other - they don't match
  7214. //
  7215. $b_match = false;
  7216. if ($s_oper != '=')
  7217. {
  7218. //
  7219. // != operator
  7220. //
  7221. $b_match = !$b_match;
  7222. $s_desc = GetMessage(MSG_IS_SAME_AS,
  7223. array("ITEM1"=>$s_friendly1,
  7224. "ITEM2"=>$s_friendly2));
  7225. }
  7226. else
  7227. $s_desc = GetMessage(MSG_IS_NOT_SAME_AS,
  7228. array("ITEM1"=>$s_friendly1,
  7229. "ITEM2"=>$s_friendly2));
  7230. if (!$b_match)
  7231. {
  7232. //
  7233. // failed
  7234. //
  7235. $s_error_mesg = $s_desc;
  7236. $b_ok = false;
  7237. }
  7238. break;
  7239. }
  7240. return ($b_ok);
  7241. }
  7242. //
  7243. // Process advanced "required" conditionals
  7244. //
  7245. function AdvancedRequired($s_cond,$i_span,$a_vars,&$s_missing,&$a_missing_list)
  7246. {
  7247. $b_ok = true;
  7248. //
  7249. // get first field name
  7250. //
  7251. list($s_fld1,$s_friendly1) = GetFriendlyName(substr($s_cond,0,$i_span));
  7252. //
  7253. // get the operator
  7254. //
  7255. $s_rem = substr($s_cond,$i_span);
  7256. $i_span = strspn($s_rem,REQUIREDOPS);
  7257. $s_oper = substr($s_rem,0,$i_span);
  7258. switch ($s_oper)
  7259. {
  7260. case '|':
  7261. case '^':
  7262. case '=':
  7263. case '!=':
  7264. //
  7265. // second component is a field name
  7266. //
  7267. list($s_fld2,$s_friendly2) = GetFriendlyName(substr($s_rem,$i_span));
  7268. if (!FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg,
  7269. $s_friendly1,$s_friendly2))
  7270. {
  7271. //
  7272. // failed
  7273. //
  7274. $s_missing .= "$s_error_mesg\n";
  7275. $a_missing_list[$s_fld1] = "$s_error_mesg";
  7276. $b_ok = false;
  7277. }
  7278. break;
  7279. default:
  7280. SendAlert(GetMessage(MSG_REQD_OPER,array("OPER"=>$s_oper)));
  7281. break;
  7282. }
  7283. return ($b_ok);
  7284. }
  7285. //
  7286. // Check the input for required values. The list of required fields
  7287. // is a comma-separated list of field names or conditionals
  7288. //
  7289. function CheckRequired($s_reqd,$a_vars,&$s_missing,&$a_missing_list)
  7290. {
  7291. global $reCaptchaProcessor;
  7292. $b_bad = false;
  7293. $a_list = TrimArray(explode(",",$s_reqd));
  7294. $s_missing = "";
  7295. $a_missing_list = array();
  7296. for ($ii = 0 ; $ii < count($a_list) ; $ii++)
  7297. {
  7298. $s_cond = $a_list[$ii];
  7299. $i_len = strlen($s_cond);
  7300. if ($i_len <= 0)
  7301. continue;
  7302. if (($i_span = strcspn($s_cond,REQUIREDOPS)) >= $i_len)
  7303. {
  7304. //
  7305. // no advanced operator; just a field name
  7306. //
  7307. list($s_fld,$s_friendly) = GetFriendlyName($s_cond);
  7308. if (TestFieldEmpty($s_fld,$a_vars,$s_mesg))
  7309. {
  7310. if ($s_mesg === "")
  7311. $s_mesg = "$s_friendly";
  7312. else
  7313. $s_mesg = "$s_friendly ($s_mesg)";
  7314. $b_bad = true;
  7315. $s_missing .= "$s_mesg\n";
  7316. $a_missing_list[$s_fld] = "$s_mesg";
  7317. }
  7318. }
  7319. elseif (!AdvancedRequired($s_cond,$i_span,$a_vars,
  7320. $s_missing,$a_missing_list))
  7321. $b_bad = true;
  7322. }
  7323. global $REQUIRE_CAPTCHA,$SPECIAL_VALUES;
  7324. //
  7325. // implement REQUIRE_CAPTCHA feature
  7326. //
  7327. if ($REQUIRE_CAPTCHA !== "")
  7328. {
  7329. if ($SPECIAL_VALUES["imgverify"] === "")
  7330. {
  7331. $s_missing .= "$REQUIRE_CAPTCHA\n";
  7332. $a_missing_list[] = "$REQUIRE_CAPTCHA";
  7333. $b_bad = true;
  7334. }
  7335. }
  7336. return (!$b_bad);
  7337. }
  7338. //
  7339. // Run a condition test
  7340. //
  7341. function RunTest($s_test,$a_vars)
  7342. {
  7343. global $aAlertInfo;
  7344. $s_op_chars = "&|^!=~#<>"; // these are the characters for the operators
  7345. $i_len = strlen($s_test);
  7346. $b_ok = true;
  7347. if ($i_len <= 0)
  7348. //
  7349. // empty test - true
  7350. //
  7351. ;
  7352. elseif ($s_test == "!")
  7353. //
  7354. // test asserts false
  7355. //
  7356. $b_ok = false;
  7357. elseif (($i_span = strcspn($s_test,$s_op_chars)) >= $i_len)
  7358. //
  7359. // no operator - just check field presence
  7360. //
  7361. $b_ok = !TestFieldEmpty($s_test,$a_vars,$s_mesg);
  7362. else
  7363. {
  7364. //
  7365. // get first field name
  7366. //
  7367. $s_fld1 = trim(substr($s_test,0,$i_span));
  7368. //
  7369. // get the operator
  7370. //
  7371. $s_rem = substr($s_test,$i_span);
  7372. $i_span = strspn($s_rem,$s_op_chars);
  7373. $s_oper = substr($s_rem,0,$i_span);
  7374. switch ($s_oper)
  7375. {
  7376. case '&':
  7377. case '|':
  7378. case '^':
  7379. case '=':
  7380. case '!=':
  7381. //
  7382. // get the second field name
  7383. //
  7384. $s_fld2 = trim(substr($s_rem,$i_span));
  7385. $b_ok = FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg);
  7386. break;
  7387. case '~':
  7388. case '!~':
  7389. //
  7390. // get the regular expression
  7391. //
  7392. $s_pat = trim(substr($s_rem,$i_span));
  7393. if (!TestFieldEmpty($s_fld1,$a_vars,$s_mesg))
  7394. $s_value = GetFieldValue($s_fld1,$a_vars);
  7395. else
  7396. $s_value = "";
  7397. //echo "<p>Pattern: '".htmlspecialchars($s_pat)."': count=".preg_match($s_pat,$s_value)."<br /></p>";
  7398. //
  7399. // match the regular expression
  7400. //
  7401. if (preg_match($s_pat,$s_value) > 0)
  7402. $b_ok = ($s_oper == '~');
  7403. else
  7404. $b_ok = ($s_oper == '!~');
  7405. if (!$b_ok)
  7406. $aAlertInfo[] = GetMessage(MSG_PAT_FAILED,array("OPER"=>$s_oper,
  7407. "PAT"=>$s_pat,
  7408. "VALUE"=>$s_value));
  7409. break;
  7410. case '#=':
  7411. case '#!=':
  7412. case '#<':
  7413. case '#>':
  7414. case '#<=':
  7415. case '#>=':
  7416. //
  7417. // numeric tests
  7418. //
  7419. $s_num = trim(substr($s_rem,$i_span));
  7420. //
  7421. // if this is a file field, get the size of the file for
  7422. // numeric tests
  7423. //
  7424. if (($s_value = GetFileSize($s_fld1)) === false)
  7425. $s_value = $a_vars[$s_fld1];
  7426. if (strpos($s_num,'.') === false)
  7427. {
  7428. //
  7429. // treat as integer
  7430. //
  7431. $m_num = (int) $s_num;
  7432. $m_fld = (int) $s_value;
  7433. }
  7434. else
  7435. {
  7436. //
  7437. // treat as floating point
  7438. //
  7439. $m_num = (float) $s_num;
  7440. $m_fld = (float) $s_value;
  7441. }
  7442. switch ($s_oper)
  7443. {
  7444. case '#=':
  7445. $b_ok = ($m_fld == $m_num);
  7446. break;
  7447. case '#!=':
  7448. $b_ok = ($m_fld != $m_num);
  7449. break;
  7450. case '#<':
  7451. $b_ok = ($m_fld < $m_num);
  7452. break;
  7453. case '#>':
  7454. $b_ok = ($m_fld > $m_num);
  7455. break;
  7456. case '#<=':
  7457. $b_ok = ($m_fld <= $m_num);
  7458. break;
  7459. case '#>=':
  7460. $b_ok = ($m_fld >= $m_num);
  7461. break;
  7462. }
  7463. break;
  7464. default:
  7465. SendAlert(GetMessage(MSG_COND_OPER,array("OPER"=>$s_oper)));
  7466. break;
  7467. }
  7468. }
  7469. return ($b_ok);
  7470. }
  7471. //
  7472. // Check the input for condition tests.
  7473. //
  7474. function CheckConditions($m_conditions,$a_vars,&$s_missing,&$a_missing_list,$m_id = false)
  7475. {
  7476. if (is_array($m_conditions))
  7477. {
  7478. //
  7479. // Sort the conditions by their numeric value. This ensures
  7480. // conditions are executed in the right order.
  7481. //
  7482. ksort($m_conditions,SORT_NUMERIC);
  7483. foreach ($m_conditions as $m_key=>$s_cond)
  7484. if (!CheckConditions($s_cond,$a_vars,$s_missing,$a_missing_list,$m_key))
  7485. return (false);
  7486. return (true);
  7487. }
  7488. $s_fld_name = "conditions".($m_id === false ? "" : ($m_id+1));
  7489. if (!is_string($m_conditions))
  7490. {
  7491. SendAlert(GetMessage(MSG_INV_COND,array("FLD"=>$s_fld_name)));
  7492. return (true); // pass invalid conditions
  7493. }
  7494. if ($m_conditions == "")
  7495. return (true); // pass empty conditions
  7496. $s_cond = $m_conditions;
  7497. //
  7498. // extract the separator characters
  7499. //
  7500. if (strlen($s_cond) < 2)
  7501. {
  7502. SendAlert(GetMessage(MSG_COND_CHARS,
  7503. array("FLD"=>$s_fld_name,"COND"=>$s_cond)));
  7504. return (true); // pass invalid conditions
  7505. }
  7506. $s_list_sep = $s_cond[0];
  7507. $s_int_sep = $s_cond[1];
  7508. $s_full_cond = $s_cond = substr($s_cond,2);
  7509. $b_bad = false;
  7510. $a_list = TrimArray(explode($s_list_sep,$s_cond));
  7511. $s_missing = "";
  7512. $a_missing_list = array();
  7513. for ($ii = 0 ; $ii < count($a_list) ; $ii++)
  7514. {
  7515. $s_cond = $a_list[$ii];
  7516. $i_len = strlen($s_cond);
  7517. if ($i_len <= 0)
  7518. continue;
  7519. //
  7520. // split the condition into its internal components
  7521. //
  7522. $a_components = TrimArray(explode($s_int_sep,$s_cond));
  7523. if (count($a_components) < 5)
  7524. {
  7525. SendAlert(GetMessage(MSG_COND_INVALID,
  7526. array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  7527. "SEP"=>$s_int_sep)));
  7528. //
  7529. // the smallest condition has 5 components
  7530. //
  7531. continue;
  7532. }
  7533. //
  7534. // first component is ignored (it's blank)
  7535. //
  7536. $a_components = array_slice($a_components,1);
  7537. switch ($a_components[0])
  7538. {
  7539. case "TEST":
  7540. if (count($a_components) > 5)
  7541. {
  7542. SendAlert(GetMessage(MSG_COND_TEST_LONG,
  7543. array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  7544. "SEP"=>$s_list_sep)));
  7545. continue;
  7546. }
  7547. if (!RunTest($a_components[1],$a_vars))
  7548. {
  7549. $s_missing .= $a_components[2]."\n";
  7550. $a_missing_list[] = $a_components[2];
  7551. $b_bad = true;
  7552. }
  7553. break;
  7554. case "IF":
  7555. if (count($a_components) < 6)
  7556. {
  7557. SendAlert(GetMessage(MSG_COND_IF_SHORT,
  7558. array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  7559. "SEP"=>$s_int_sep)));
  7560. continue;
  7561. }
  7562. if (count($a_components) > 7)
  7563. {
  7564. SendAlert(GetMessage(MSG_COND_IF_LONG,
  7565. array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  7566. "SEP"=>$s_list_sep)));
  7567. continue;
  7568. }
  7569. if (RunTest($a_components[1],$a_vars))
  7570. $b_test = RunTest($a_components[2],$a_vars);
  7571. else
  7572. $b_test = RunTest($a_components[3],$a_vars);
  7573. if (!$b_test)
  7574. {
  7575. $s_missing .= $a_components[4]."\n";
  7576. $a_missing_list[] = $a_components[4];
  7577. $b_bad = true;
  7578. }
  7579. break;
  7580. default:
  7581. SendAlert(GetMessage(MSG_COND_UNK,
  7582. array("FLD"=>$s_fld_name,"COND"=>$s_cond,
  7583. "CMD"=>$a_components[0])));
  7584. break;
  7585. }
  7586. }
  7587. return (!$b_bad);
  7588. }
  7589. //
  7590. // Return a formatted list of the given environment variables.
  7591. //
  7592. function GetEnvVars($list,$s_line_feed)
  7593. {
  7594. global $VALID_ENV,$aServerVars;
  7595. $output = "";
  7596. for ($ii = 0 ; $ii < count($list) ; $ii++)
  7597. {
  7598. $name = $list[$ii];
  7599. if ($name && array_search($name,$VALID_ENV,true) !== false)
  7600. {
  7601. //
  7602. // if the environment variable is empty or non-existent, try
  7603. // looking for the value in the server vars.
  7604. //
  7605. if (($s_value = getenv($name)) === "" || $s_value === false)
  7606. if (isset($aServerVars[$name]))
  7607. $s_value = $aServerVars[$name];
  7608. else
  7609. $s_value = "";
  7610. $output .= $name."=".$s_value.$s_line_feed;
  7611. }
  7612. }
  7613. return ($output);
  7614. }
  7615. //
  7616. // open a socket connection to a filter and post the data there
  7617. // RJR: TO DO: re-implement using NetIO
  7618. //
  7619. function SocketFilter($filter,$a_filter_info,$m_data)
  7620. {
  7621. static $b_in_here = false;
  7622. global $php_errormsg;
  7623. //
  7624. // prevent recursive errors
  7625. //
  7626. if ($b_in_here)
  7627. return ("<DATA DISCARDED>");
  7628. $b_in_here = true;
  7629. $a_errors = array();
  7630. if (!isset($a_filter_info["site"]))
  7631. $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"site"));
  7632. else
  7633. $s_site = $a_filter_info["site"];
  7634. if (!isset($a_filter_info["port"]))
  7635. $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"port"));
  7636. else
  7637. $i_port = (int) $a_filter_info["port"];
  7638. if (!isset($a_filter_info["path"]))
  7639. $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"path"));
  7640. else
  7641. $s_path = $a_filter_info["path"];
  7642. if (!isset($a_filter_info["params"]))
  7643. $a_params = array();
  7644. elseif (!is_array($a_filter_info["params"]))
  7645. $a_errors[] = GetMessage(MSG_NEED_ARRAY,array("ITEM"=>"params"));
  7646. else
  7647. $a_params = $a_filter_info["params"];
  7648. if (!empty($a_errors))
  7649. {
  7650. Error("bad_filter",GetMessage(MSG_FILTER_WRONG,array(
  7651. "FILTER"=>$filter,
  7652. "ERRORS"=>implode(', ',$a_errors))),false,false);
  7653. exit;
  7654. }
  7655. //
  7656. // ready to build the socket - we need a longer time limit for the
  7657. // script if we're doing this; we allow 30 seconds for the connection
  7658. // (should be instantaneous, especially if it's the same domain)
  7659. //
  7660. set_time_limit(60);
  7661. @ $f_sock = fsockopen($s_site,$i_port,$i_errno,$s_errstr,30);
  7662. if ($f_sock === false)
  7663. {
  7664. Error("filter_connect",GetMessage(MSG_FILTER_CONNECT,array(
  7665. "FILTER"=>$filter,
  7666. "SITE"=>$s_site,
  7667. "ERRNUM"=>$i_errno,
  7668. "ERRSTR"=>"$s_errstr (".CheckString($php_errormsg).")")),
  7669. false,false);
  7670. exit;
  7671. }
  7672. //
  7673. // build the data to send
  7674. //
  7675. $m_request_data = array();
  7676. $i_count = 0;
  7677. foreach ($a_params as $m_var)
  7678. {
  7679. $i_count++;
  7680. //
  7681. // if the parameter spec is an array, process it specially;
  7682. // it must have "name" and "file" elements
  7683. //
  7684. if (is_array($m_var))
  7685. {
  7686. if (!isset($m_var["name"]))
  7687. {
  7688. Error("bad_filter",GetMessage(MSG_FILTER_PARAM,
  7689. array("FILTER"=>$filter,
  7690. "NUM"=>$i_count,
  7691. "NAME"=>"name")),false,false);
  7692. fclose($f_sock);
  7693. exit;
  7694. }
  7695. $s_name = $m_var["name"];
  7696. if (!isset($m_var["file"]))
  7697. {
  7698. Error("bad_filter",GetMessage(MSG_FILTER_PARAM,
  7699. array("FILTER"=>$filter,
  7700. "NUM"=>$i_count,
  7701. "NAME"=>"file")),false,false);
  7702. fclose($f_sock);
  7703. exit;
  7704. }
  7705. //
  7706. // open the file and read its contents
  7707. //
  7708. @ $fp = fopen($m_var["file"],"r");
  7709. if ($fp === false)
  7710. {
  7711. Error("filter_error",GetMessage(MSG_FILTER_OPEN_FILE,
  7712. array("FILTER"=>$filter,
  7713. "FILE"=>$m_var["file"],
  7714. "ERROR"=>CheckString($php_errormsg))),false,false);
  7715. fclose($f_sock);
  7716. exit;
  7717. }
  7718. $s_data = "";
  7719. $n_lines = 0;
  7720. while (!feof($fp))
  7721. {
  7722. if (($s_line = fgets($fp,2048)) === false)
  7723. if (feof($fp))
  7724. break;
  7725. else
  7726. {
  7727. Error("filter_error",GetMessage(MSG_FILTER_FILE_ERROR,
  7728. array("FILTER"=>$filter,
  7729. "FILE"=>$m_var["file"],
  7730. "ERROR"=>CheckString($php_errormsg),
  7731. "NLINES"=>$n_lines)),false,false);
  7732. fclose($f_sock);
  7733. exit;
  7734. }
  7735. $s_data .= $s_line;
  7736. $n_lines++;
  7737. }
  7738. fclose($fp);
  7739. $m_request_data[] = "$s_name=".urlencode($s_data);
  7740. }
  7741. else
  7742. $m_request_data[] = (string) $m_var;
  7743. }
  7744. //
  7745. // add the data
  7746. //
  7747. if (is_array($m_data))
  7748. $m_request_data[] = "data=".urlencode(implode(BODY_LF,$m_data));
  7749. else
  7750. $m_request_data[] = "data=".urlencode($m_data);
  7751. $s_request = implode("&",$m_request_data);
  7752. if (($i_pos = strpos($s_site,"://")) !== false)
  7753. $s_site_name = substr($s_site,$i_pos+3);
  7754. else
  7755. $s_site_name = $s_site;
  7756. fputs($f_sock,"POST $s_path HTTP/1.0\r\n");
  7757. fputs($f_sock,"Host: $s_site_name\r\n");
  7758. fputs($f_sock,"Content-Type: application/x-www-form-urlencoded\r\n");
  7759. fputs($f_sock,"Content-Length: ".strlen($s_request)."\r\n");
  7760. fputs($f_sock,"\r\n");
  7761. fputs($f_sock,"$s_request\r\n");
  7762. //
  7763. // now read the response
  7764. //
  7765. $m_hdr = "";
  7766. $m_data = "";
  7767. $b_in_hdr = true;
  7768. $b_ok = false;
  7769. while (!feof($f_sock))
  7770. {
  7771. if (($s_line = fgets($f_sock,2048)) === false)
  7772. if (feof($f_sock))
  7773. break;
  7774. else
  7775. {
  7776. Error("filter_failed",GetMessage(MSG_FILTER_READ_ERROR,
  7777. array("FILTER"=>$filter,
  7778. "ERROR"=>CheckString($php_errormsg))),false,false);
  7779. fclose($f_sock);
  7780. exit;
  7781. }
  7782. //
  7783. // look for an "__OK__" line
  7784. //
  7785. if (trim($s_line) == "__OK__")
  7786. $b_ok = true;
  7787. elseif ($b_in_hdr)
  7788. {
  7789. //
  7790. // blank line signals end of header
  7791. //
  7792. if (trim($s_line) == "")
  7793. $b_in_hdr = false;
  7794. else
  7795. $m_hdr .= $s_line;
  7796. }
  7797. else
  7798. $m_data .= $s_line;
  7799. }
  7800. //
  7801. // if not OK, then report error
  7802. //
  7803. if (!$b_ok)
  7804. {
  7805. Error("filter_failed",GetMessage(MSG_FILTER_NOT_OK,
  7806. array("FILTER"=>$filter,
  7807. "DATA"=>$m_data)),false,false);
  7808. fclose($f_sock);
  7809. exit;
  7810. }
  7811. fclose($f_sock);
  7812. $b_in_here = false;
  7813. return ($m_data);
  7814. }
  7815. //
  7816. // run data through a supported filter
  7817. //
  7818. function Filter($filter,$m_data)
  7819. {
  7820. global $FILTERS,$SOCKET_FILTERS;
  7821. global $php_errormsg;
  7822. static $b_in_here = false;
  7823. //
  7824. // prevent recursive errors
  7825. //
  7826. if ($b_in_here)
  7827. return ("<DATA DISCARDED>");
  7828. $b_in_here = true;
  7829. //
  7830. // Any errors sent in an alert are flagged to not run through the
  7831. // filter - this also means the user's data won't be included in the
  7832. // alert.
  7833. // The reason for this is that the Filter is typically an encryption
  7834. // program. If the filter fails, then sending the user's data in
  7835. // clear text in an alert breaks the security of having encryption
  7836. // in the first place!
  7837. //
  7838. //
  7839. // find the filter
  7840. //
  7841. if (!isset($FILTERS[$filter]) || $FILTERS[$filter] == "")
  7842. {
  7843. //
  7844. // check for SOCKET_FILTERS
  7845. //
  7846. if (!isset($SOCKET_FILTERS[$filter]) || $SOCKET_FILTERS[$filter] == "")
  7847. {
  7848. ErrorWithIgnore("bad_filter",GetMessage(MSG_FILTER_UNK,
  7849. array("FILTER"=>$filter)),false,false);
  7850. exit;
  7851. }
  7852. $m_data = SocketFilter($filter,$SOCKET_FILTERS[$filter],$m_data);
  7853. }
  7854. elseif ($FILTERS[$filter] == "null")
  7855. //
  7856. // do nothing - just return the original data unchanged
  7857. //
  7858. ;
  7859. elseif ($FILTERS[$filter] == "csv")
  7860. $m_data = BuiltinFilterCSV();
  7861. else
  7862. {
  7863. $cmd = $FILTERS[$filter];
  7864. //
  7865. // get the program name - assumed to be the first blank-separated word
  7866. //
  7867. $a_words = preg_split('/\s+/',$cmd);
  7868. $prog = $a_words[0];
  7869. $s_cwd = getcwd();
  7870. //
  7871. // change to the directory that contains the filter program
  7872. //
  7873. $dirname = dirname($prog);
  7874. if ($dirname != "" && $dirname != "." && !chdir($dirname))
  7875. {
  7876. Error("chdir_filter",GetMessage(MSG_FILTER_CHDIR,
  7877. array("DIR"=>$dirname,"FILTER"=>$filter,
  7878. "ERROR"=>CheckString($php_errormsg))),false,false);
  7879. exit;
  7880. }
  7881. //
  7882. // the output of the filter goes to a temporary file; this works
  7883. // OK on Windows too, even with the Unix shell syntax.
  7884. //
  7885. $temp_file = GetTempName("FMF");
  7886. $temp_error_file = GetTempName("FME");
  7887. $cmd = "$cmd >$temp_file 2>$temp_error_file";
  7888. //
  7889. // start the filter
  7890. //
  7891. $pipe = popen($cmd,"w");
  7892. if ($pipe === false)
  7893. {
  7894. $s_sv_err = CheckString($php_errormsg);
  7895. $err = join('',file($temp_error_file));
  7896. unlink($temp_file);
  7897. unlink($temp_error_file);
  7898. Error("filter_not_found",GetMessage(MSG_FILTER_NOTFOUND,
  7899. array("CMD"=>$cmd,"FILTER"=>$filter,
  7900. "ERROR"=>$s_sv_err)),false,false,$err);
  7901. exit;
  7902. }
  7903. //
  7904. // write the data to the filter
  7905. //
  7906. if (is_array($m_data))
  7907. fwrite($pipe,implode(BODY_LF,$m_data));
  7908. else
  7909. fwrite($pipe,$m_data);
  7910. if (($i_st = pclose($pipe)) != 0)
  7911. {
  7912. $s_sv_err = CheckString($php_errormsg);
  7913. $err = join('',file($temp_error_file));
  7914. unlink($temp_file);
  7915. unlink($temp_error_file);
  7916. Error("filter_failed",GetMessage(MSG_FILTER_ERROR,
  7917. array("FILTER"=>$filter,
  7918. "ERROR"=>$s_sv_err,
  7919. "STATUS"=>$i_st)),false,false,$err);
  7920. exit;
  7921. }
  7922. //
  7923. // read in the filter's output and return as the data to be sent
  7924. //
  7925. $m_data = join('',file($temp_file));
  7926. unlink($temp_error_file);
  7927. unlink($temp_file);
  7928. //
  7929. // return to previous directory
  7930. //
  7931. chdir($s_cwd);
  7932. }
  7933. $b_in_here = false;
  7934. return ($m_data);
  7935. }
  7936. /*
  7937. * Function: FilterFiles
  7938. * Parameters: $a_files list of file uploads to filter
  7939. * Returns: void
  7940. * Description:
  7941. * Run the given files through any filter for which they are specified.
  7942. */
  7943. function FilterFiles(&$a_files)
  7944. {
  7945. global $SPECIAL_VALUES;
  7946. FMDebug("FilterFiles ".count($a_files));
  7947. if (!GetFilterSpec($s_filter,$a_filter_list,true) || $a_filter_list === false)
  7948. //
  7949. // no filter or file fields to filter
  7950. //
  7951. return;
  7952. if (($s_mime = GetFilterAttrib($s_filter,"MIME")) === false)
  7953. $s_mime = "";
  7954. //
  7955. // now, for each file, check if it is specified in the filter list
  7956. //
  7957. foreach ($a_files as $s_fld=>$a_upload)
  7958. {
  7959. FMDebug("Checking $s_fld");
  7960. if (!IsUploadedFile($a_upload))
  7961. {
  7962. FMDebug("Not uploaded");
  7963. //
  7964. // failed security check
  7965. //
  7966. continue;
  7967. }
  7968. if (!in_array($s_fld,$a_filter_list,true))
  7969. {
  7970. FMDebug("Not to be filtered");
  7971. continue;
  7972. }
  7973. /*** not sure what to do with this....
  7974. if (isset($a_upload["error"]))
  7975. //
  7976. // there was an upload error
  7977. //
  7978. continue;
  7979. ***/
  7980. //
  7981. // this file upload has been specified for filtering
  7982. //
  7983. $s_file_name = $a_upload["tmp_name"];
  7984. //
  7985. // check if the file has been saved elsewhere
  7986. //
  7987. if (isset($a_upload["saved_as"]) && !empty($a_upload["saved_as"]))
  7988. $s_file_name = $a_upload["saved_as"];
  7989. FMDebug("File name is $s_file_name");
  7990. //
  7991. // read in the file
  7992. //
  7993. if (($s_data = ReadInFile($s_file_name,"upload")) === false)
  7994. Error("filter_files",GetMessage(MSG_FILE_UPLOAD_ERR_UNK,array("ERRNO"=>"reading $s_fld")),false,false);
  7995. //
  7996. // filter and write it back out to the same file
  7997. //
  7998. $s_data = Filter($s_filter,$s_data);
  7999. if (!WriteOutFile($s_file_name,$s_data,"upload"))
  8000. Error("filter_files",GetMessage(MSG_FILE_UPLOAD_ERR_UNK,array("ERRNO"=>"writing $s_fld")),false,false);
  8001. //
  8002. // update size and MIME type for this upload
  8003. //
  8004. $a_upload["size"] = strlen($s_data);
  8005. if ($s_mime !== "")
  8006. $a_upload["type"] = $s_mime;
  8007. $a_files[$s_fld] = $a_upload;
  8008. }
  8009. }
  8010. /*
  8011. * Function: ReadInFile
  8012. * Parameters: $s_file_name the name of the file
  8013. * $s_file_error_type type of file for any error message
  8014. * $b_text if true, read file as text
  8015. * Returns: mixed the entire contents of the file
  8016. * as a string, or false on error
  8017. * Description:
  8018. * Reads the contents of a file into a string.
  8019. */
  8020. function ReadInFile($s_file_name,$s_file_error_type,$b_text = false)
  8021. {
  8022. global $php_errormsg;
  8023. if (($fp = @fopen($s_file_name,"r".($b_text ? "t" : "b"))) === false)
  8024. {
  8025. SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_file_name,
  8026. "TYPE"=>"read ".$s_file_error_type,
  8027. "ERROR"=>CheckString($php_errormsg))));
  8028. return (false);
  8029. }
  8030. $s_data = "";
  8031. while (!feof($fp))
  8032. $s_data .= fread($fp,8192);
  8033. @fclose($fp);
  8034. return ($s_data);
  8035. }
  8036. /*
  8037. * Function: WriteOutFile
  8038. * Parameters: $s_file_name the name of the file
  8039. * $s_data the data to write
  8040. * $s_file_error_type type of file for any error message
  8041. * $b_text if true, read file as text
  8042. * Returns: bool true on success, otherwise false
  8043. * Description:
  8044. * Writes the contents of a file from a string.
  8045. */
  8046. function WriteOutFile($s_file_name,$s_data,$s_file_error_type,$b_text = false)
  8047. {
  8048. global $php_errormsg;
  8049. if (($fp = @fopen($s_file_name,"w".($b_text ? "t" : "b"))) === false)
  8050. {
  8051. SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_file_name,
  8052. "TYPE"=>"write ".$s_file_error_type,
  8053. "ERROR"=>CheckString($php_errormsg))));
  8054. return (false);
  8055. }
  8056. if (fwrite($fp,$s_data) < strlen($s_data))
  8057. {
  8058. @fclose($fp);
  8059. return (false);
  8060. }
  8061. @fclose($fp);
  8062. return (true);
  8063. }
  8064. /*
  8065. * Class: CSVFormat
  8066. * Description:
  8067. * Manages formatting of CSV content.
  8068. */
  8069. class CSVFormat
  8070. {
  8071. var $_cSep; /* field separator character */
  8072. var $_cQuote; /* field quote character */
  8073. var $_cIntSep; /* internal separator character (for lists) */
  8074. var $_sEscPolicy; /* escape processing policy */
  8075. var $_sCleanFunc; /* cleaning function for fields */
  8076. /*
  8077. * Method: CSVFormat ctor
  8078. * Parameters: $c_sep the field separator
  8079. * $c_quote the quote character to use
  8080. * $c_int_sep the internal field separator to use
  8081. * $s_esc_policy escape processing policy to use
  8082. * $s_clean_func a cleaning function
  8083. * Returns: n/a
  8084. * Description:
  8085. * Constructs the object.
  8086. */
  8087. function CSVFormat($c_sep = ',',$c_quote = '"',$c_int_sep = ';',
  8088. $s_esc_policy = "backslash",$s_clean_func = NULL)
  8089. {
  8090. $this->SetSep($c_sep);
  8091. $this->SetQuote($c_quote);
  8092. $this->SetIntSep($c_int_sep);
  8093. $this->SetEscPolicy($s_esc_policy);
  8094. $this->SetCleanFunc($s_clean_func);
  8095. }
  8096. /*
  8097. * Method: SetEscPolicy
  8098. * Parameters: $s_esc_policy a string specifying the escape processing
  8099. * policy to use
  8100. * Returns: void
  8101. * Description:
  8102. * Set the escape processing policy.
  8103. */
  8104. function SetEscPolicy($s_esc_policy)
  8105. {
  8106. switch ($s_esc_policy)
  8107. {
  8108. default: /* should generate a warning */
  8109. case "backslash":
  8110. $this->_sEscPolicy = "b";
  8111. break;
  8112. case "double":
  8113. $this->_sEscPolicy = "d";
  8114. break;
  8115. case "strip":
  8116. $this->_sEscPolicy = "s";
  8117. break;
  8118. case "conv":
  8119. $this->_sEscPolicy = "c";
  8120. break;
  8121. }
  8122. }
  8123. /*
  8124. * Method: SetSep
  8125. * Parameters: $c_sep the separator character to use
  8126. * Returns: void
  8127. * Description:
  8128. * Set the separator character for between fields.
  8129. */
  8130. function SetSep($c_sep)
  8131. {
  8132. $this->_cSep = $c_sep;
  8133. }
  8134. /*
  8135. * Method: SetQuote
  8136. * Parameters: $c_quote the quote character to use
  8137. * Returns: void
  8138. * Description:
  8139. * Set the quote character for quoting fields.
  8140. */
  8141. function SetQuote($c_quote)
  8142. {
  8143. $this->_cQuote = $c_quote;
  8144. }
  8145. /*
  8146. * Method: SetIntSep
  8147. * Parameters: $c_int_sep the internal separator character to use
  8148. * Returns: void
  8149. * Description:
  8150. * Set the internal separator character for inside fields.
  8151. */
  8152. function SetIntSep($c_int_sep)
  8153. {
  8154. $this->_cIntSep = $c_int_sep;
  8155. }
  8156. /*
  8157. * Method: SetCleanFunc
  8158. * Parameters: $s_clean_func the name of a cleaning function (can be NULL)
  8159. * Returns: void
  8160. * Description:
  8161. * Set the cleaning function for fields.
  8162. */
  8163. function SetCleanFunc($s_clean_func)
  8164. {
  8165. $this->_sCleanFunc = $s_clean_func;
  8166. }
  8167. /*
  8168. * Method: _Escape
  8169. * Parameters: $m_value the field value; string or array of strings
  8170. * Returns: mixed the field value escaped according to the
  8171. * escape processing policy
  8172. * Description:
  8173. * Escapes a field value according to the configured requirements.
  8174. */
  8175. function _Escape($m_value)
  8176. {
  8177. switch ($this->_sEscPolicy)
  8178. {
  8179. default: /* should generate an error */
  8180. case "b":
  8181. /*
  8182. * 'backslash' escape policy: replace \ with \\ and
  8183. * " with \"
  8184. */
  8185. $m_value = str_replace("\\","\\\\",$m_value);
  8186. $m_value = str_replace($this->_cQuote,"\\".$this->_cQuote,
  8187. $m_value);
  8188. break;
  8189. case "d":
  8190. /*
  8191. * 'double' escape policy: replace " with ""
  8192. * This is suitable for Microsoft apps such as Excel
  8193. * and Access. It also meets the specification of
  8194. * RFC4180, though this RFC only specified double
  8195. * quotes whereas we handle any quote character.
  8196. */
  8197. $m_value = str_replace($this->_cQuote,
  8198. $this->_cQuote.$this->_cQuote,$m_value);
  8199. break;
  8200. case "s":
  8201. /*
  8202. * 'strip' escape policy: strip quotes
  8203. */
  8204. $m_value = str_replace($this->_cQuote,"",$m_value);
  8205. break;
  8206. case "c":
  8207. /*
  8208. * 'conv' escape policy: convert quotes to the other quotes
  8209. */
  8210. switch ($this->_cQuote)
  8211. {
  8212. case '"':
  8213. /*
  8214. * convert double quotes in the data to single quotes
  8215. */
  8216. $m_value = str_replace("\"","'",$m_value);
  8217. break;
  8218. case '\'':
  8219. /*
  8220. * convert single quotes in the data to double quotes
  8221. */
  8222. $m_value = str_replace("'","\"",$m_value);
  8223. break;
  8224. default:
  8225. /*
  8226. * otherwise, leave the data unchanged
  8227. */
  8228. break;
  8229. }
  8230. break;
  8231. }
  8232. return ($m_value);
  8233. }
  8234. /*
  8235. * Method: _Format
  8236. * Parameters: $s_value the string value to format
  8237. * $s_format a format specification
  8238. * a list of characters:
  8239. * c CleanValue
  8240. * s force to be a string
  8241. * r remove carriage returns
  8242. * Returns: string the formatted value
  8243. * Description:
  8244. * Formats a value.
  8245. */
  8246. function _Format($s_value,$s_format = "")
  8247. {
  8248. $s_value = $this->_Escape($s_value);
  8249. $s_prefix = "";
  8250. /*
  8251. * now implement any special formatting to overcome
  8252. * problems with importing
  8253. */
  8254. $i_len = strlen($s_format);
  8255. for ($ii = 0 ; $ii < $i_len ; $ii++)
  8256. {
  8257. switch ($s_format[$ii])
  8258. {
  8259. case "c":
  8260. /*
  8261. * implement "c" formatting - CleanValue
  8262. */
  8263. $s_value = CleanValue($s_value);
  8264. break;
  8265. case "r":
  8266. /*
  8267. * implement "r" formatting - remove
  8268. * carriage returns. Useful for Microsoft Excel
  8269. */
  8270. $s_value = str_replace("\r","",$s_value);
  8271. break;
  8272. case "s":
  8273. /*
  8274. * implement "s" formatting - force
  8275. * a value to be a string (by making it a string
  8276. * formula). Useful for Microsoft Excel and OpenOffice
  8277. * spreadsheet, which don't understand numeric phone
  8278. * numbers, for example.
  8279. */
  8280. if (strlen($s_value) > 0)
  8281. $s_prefix = "=";
  8282. break;
  8283. }
  8284. }
  8285. return ($s_prefix.$this->_cQuote.$s_value.$this->_cQuote);
  8286. }
  8287. /*
  8288. * Method: _GetColumn
  8289. * Parameters: $s_col_spec a column specification
  8290. * Returns: array the column name and the format specifier, if
  8291. * any
  8292. * Description:
  8293. * Returns the column name and any format specifier.
  8294. */
  8295. function _GetColumn($s_col_spec)
  8296. {
  8297. $s_format = "";
  8298. if (($i_pos = strpos($s_col_spec,":")) !== false)
  8299. {
  8300. $s_col_name = trim(substr($s_col_spec,0,$i_pos));
  8301. $s_format = trim(substr($s_col_spec,$i_pos+1));
  8302. }
  8303. else
  8304. $s_col_name = $s_col_spec;
  8305. return (array($s_col_name,$s_format));
  8306. }
  8307. /*
  8308. * Method: MakeCSVRecord
  8309. * Parameters: $a_column_list a list of column names (field names) to
  8310. * include; can include format specifiers
  8311. * $a_vars raw data array indexed by column name
  8312. * (field name).
  8313. * A data value can be a string or an array
  8314. * of strings.
  8315. * Returns: string the comma-separated value
  8316. * Description:
  8317. * Creates a single CSV record for a list of columns.
  8318. */
  8319. function MakeCSVRecord($a_column_list,$a_vars)
  8320. {
  8321. $s_rec = "";
  8322. $n_columns = count($a_column_list);
  8323. for ($ii = 0 ; $ii < $n_columns ; $ii++)
  8324. {
  8325. list($s_col_name,$s_format) = $this->_GetColumn($a_column_list[$ii]);
  8326. /*
  8327. * if a column is specified it must be included, even if there
  8328. * is no data for it.
  8329. */
  8330. $s_value = GetFieldValue($s_col_name,$a_vars,$this->_cIntSep);
  8331. if (isset($this->_sCleanFunc))
  8332. {
  8333. $s_func = $this->_sCleanFunc;
  8334. $s_value = $s_func($s_value);
  8335. }
  8336. $s_value = $this->_Format($s_value,$s_format);
  8337. if ($ii > 0)
  8338. /*
  8339. * prepend the separator from the second field onwards
  8340. */
  8341. $s_rec .= $this->_cSep;
  8342. $s_rec .= $s_value;
  8343. }
  8344. return ($s_rec);
  8345. }
  8346. /*
  8347. * Method: MakeHeading
  8348. * Parameters: $a_column_list a list of column names (field names) to
  8349. * include
  8350. * Returns: string the comma-separated heading record
  8351. * Description:
  8352. * Creates a heading record for the CSV data.
  8353. */
  8354. function MakeHeading($a_column_list)
  8355. {
  8356. $s_rec = "";
  8357. $n_columns = count($a_column_list);
  8358. for ($ii = 0 ; $ii < $n_columns ; $ii++)
  8359. {
  8360. list($s_col_name,$s_format) = $this->_GetColumn($a_column_list[$ii]);
  8361. $s_value = $this->_Format($s_col_name);
  8362. if ($ii > 0)
  8363. /*
  8364. * prepend the separator from the second field onwards
  8365. */
  8366. $s_rec .= $this->_cSep;
  8367. $s_rec .= $s_value;
  8368. }
  8369. return ($s_rec);
  8370. }
  8371. };
  8372. /*
  8373. * Built-in filter. Generates CSV (comma separated values) content from
  8374. * the submitted fields. The special field "filter_fields" determines
  8375. * which fields to include in the CSV content.
  8376. * The following options are support in "filter_options":
  8377. * CSVHeading if set, includes a heading line first with the field names
  8378. * CSVSep specifies a separator character instead of comma
  8379. * CSVIntSep specifies an internal separator character for lists
  8380. * CSVQuote specifies the character to use to quote each column; default
  8381. * is double quotes
  8382. * CSVEscPolicy controls the way quotes are escaped in the data. Supported
  8383. * values are: backslash (the default),double,strip
  8384. * CSVRaw if set, then the fields are recorded as raw values and
  8385. * are *not* cleaned according to FormMail's normal field
  8386. * cleaning process.
  8387. * If the "filter_fields" field does not exist, then the "csvcolumns" field is
  8388. * used instead. If neither exist, then all fields are included along with
  8389. * a Heading line.
  8390. */
  8391. function BuiltinFilterCSV()
  8392. {
  8393. global $aAllRawValues,$aRawDataValues,$SPECIAL_VALUES,$CSVLINE;
  8394. $b_heading = false;
  8395. $a_column_list = array();
  8396. $s_cols = $SPECIAL_VALUES["filter_fields"];
  8397. if (!isset($s_cols) || empty($s_cols) || !is_string($s_cols))
  8398. {
  8399. $s_cols = $SPECIAL_VALUES["csvcolumns"];
  8400. if (!isset($s_cols) || empty($s_cols) || !is_string($s_cols))
  8401. {
  8402. /*
  8403. * neither filter_fields nor csvcolumns defined - get all
  8404. * columns
  8405. */
  8406. $s_cols = "";
  8407. /*
  8408. * special case - include these two special fields
  8409. */
  8410. $a_column_list = array("email","realname");
  8411. /*
  8412. * now include all the data fields
  8413. */
  8414. $a_column_list = array_merge($a_column_list,
  8415. array_keys($aRawDataValues));
  8416. $b_heading = true;
  8417. }
  8418. }
  8419. if (empty($a_column_list))
  8420. $a_column_list = TrimArray(explode(",",$s_cols));
  8421. $csv_format = new CSVFormat();
  8422. /*
  8423. * get the various options and set them
  8424. */
  8425. $m_temp = GetFilterOption("CSVQuote");
  8426. if (isset($m_temp))
  8427. $csv_format->SetQuote($m_temp);
  8428. $m_temp = GetFilterOption("CSVSep");
  8429. if (isset($m_temp))
  8430. $csv_format->SetSep($m_temp);
  8431. $m_temp = GetFilterOption("CSVIntSep");
  8432. if (isset($m_temp))
  8433. $csv_format->SetIntSep($m_temp);
  8434. $m_temp = GetFilterOption("CSVEscPolicy");
  8435. if (isset($m_temp))
  8436. $csv_format->SetEscPolicy($m_temp);
  8437. $m_temp = GetFilterOption("CSVHeading");
  8438. if (isset($m_temp))
  8439. $b_heading = true;
  8440. /*
  8441. * clean fields unless CSVRaw is specified
  8442. */
  8443. $m_temp = GetFilterOption("CSVRaw");
  8444. if (!isset($m_temp))
  8445. $csv_format->SetCleanFunc(create_function('$m_value',
  8446. 'return CleanValue($m_value);'));
  8447. $s_csv = $csv_format->MakeCSVRecord($a_column_list,$aAllRawValues);
  8448. if ($b_heading)
  8449. {
  8450. $s_head = $csv_format->MakeHeading($a_column_list);
  8451. /*
  8452. * return the heading and the record with $CSVLINE as record separator
  8453. */
  8454. return ($s_head.$CSVLINE.$s_csv.$CSVLINE);
  8455. }
  8456. else
  8457. /*
  8458. * return this record with $CSVLINE appended
  8459. */
  8460. return ($s_csv.$CSVLINE);
  8461. }
  8462. $aSubstituteErrors = array();
  8463. $SubstituteFields = NULL;
  8464. $sSubstituteMissing = NULL;
  8465. //
  8466. // Run htmlspecialchars on every value in an array.
  8467. //
  8468. function ArrayHTMLSpecialChars($a_list)
  8469. {
  8470. $a_new = array();
  8471. foreach ($a_list as $m_key=>$m_value)
  8472. if (is_array($m_value))
  8473. $a_new[$m_key] = ArrayHTMLSpecialChars($m_value);
  8474. else
  8475. $a_new[$m_key] = htmlspecialchars($m_value);
  8476. return ($a_new);
  8477. }
  8478. //
  8479. // Truncate a value based on the specified maximums.
  8480. //
  8481. function Truncate($s_value,$n_max_chars,$n_max_lines)
  8482. {
  8483. if ($n_max_lines > 0)
  8484. {
  8485. $a_lines = explode("\n",$s_value);
  8486. if (count($a_lines) > $n_max_lines)
  8487. {
  8488. $a_lines = array_slice($a_lines,0,$n_max_lines);
  8489. $s_value = implode("\n",$a_lines);
  8490. $s_value .= "...";
  8491. }
  8492. }
  8493. if ($n_max_chars > 0)
  8494. {
  8495. $a_lines = explode("\n",$s_value);
  8496. for ($ii = 0 ; $ii < count($a_lines) ; $ii++)
  8497. {
  8498. $n_len = strlen($a_lines[$ii]);
  8499. $s_eol = "";
  8500. if (substr($a_lines[$ii],-1) == "\n")
  8501. {
  8502. $n_len--;
  8503. $s_eol = "\n";
  8504. }
  8505. if ($n_len > $n_max_chars)
  8506. $a_lines[$ii] = substr($a_lines[$ii],0,$n_max_chars)."...".$s_eol;
  8507. }
  8508. $s_value = implode("\n",$a_lines);
  8509. }
  8510. return ($s_value);
  8511. }
  8512. //
  8513. // Worker function for SubstituteValue and SubstituteValueForPage.
  8514. // Returns the value of the matched variable name.
  8515. // Variables are searched for in the global $SubstituteFields.
  8516. // If no such variable exists, an error is reported or the given
  8517. // replacement string is used.
  8518. // Errors are stored in the global $aSubstituteErrors.
  8519. //
  8520. function SubstituteValueWorker($a_matches,$s_repl,$b_html = true)
  8521. {
  8522. global $aSubstituteErrors,$SubstituteFields,$SPECIAL_VALUES;
  8523. $b_insert_br = true; // option to put "<br />" tags before newlines in HTML templates
  8524. $n_max_chars = 0;
  8525. $n_max_lines = 0;
  8526. $s_list_sep = $SPECIAL_VALUES['template_list_sep'];
  8527. $b_text_subs = false;
  8528. $s_name = $a_matches[0];
  8529. assert(strlen($s_name) > 1 && $s_name[0] == '$');
  8530. $s_name = substr($s_name,1);
  8531. if (($i_len = strlen($s_name)) > 0 && $s_name[0] == '{')
  8532. {
  8533. assert($s_name[$i_len-1] == '}');
  8534. $s_name = substr($s_name,1,-1);
  8535. //
  8536. // grab any processing options
  8537. //
  8538. $a_args = explode(":",$s_name);
  8539. $s_name = $a_args[0];
  8540. if (($n_args = count($a_args)) > 1)
  8541. {
  8542. for ($ii = 1 ; $ii < $n_args ; $ii++)
  8543. {
  8544. //
  8545. // some options are followed by =X
  8546. // where X is a value
  8547. //
  8548. $s_param = "";
  8549. if (($i_pos = strpos($a_args[$ii],'=')) !== false)
  8550. {
  8551. $s_param = substr($a_args[$ii],$i_pos+1);
  8552. $s_opt = substr($a_args[$ii],0,$i_pos);
  8553. }
  8554. else
  8555. $s_opt = $a_args[$ii];
  8556. switch ($s_opt)
  8557. {
  8558. case "nobr":
  8559. $b_insert_br = false;
  8560. break;
  8561. case "chars":
  8562. if ($s_param !== "")
  8563. $n_max_chars = (int) $s_param;
  8564. break;
  8565. case "lines":
  8566. if ($s_param !== "")
  8567. $n_max_lines = (int) $s_param;
  8568. break;
  8569. case "sep":
  8570. if ($s_param !== "")
  8571. $s_list_sep = $s_param;
  8572. break;
  8573. case "subs":
  8574. $b_text_subs = true;
  8575. break;
  8576. }
  8577. }
  8578. }
  8579. }
  8580. $s_value = "";
  8581. if ($SubstituteFields->IsFieldSet($s_name) &&
  8582. !$SubstituteFields->TestFieldEmpty($s_name,$s_mesg))
  8583. {
  8584. if ($b_html)
  8585. //
  8586. // Up to and including version 8.24, the code used
  8587. // htmlspecialchars. Version 8.28 caused UTF-8 template
  8588. // processing to break, because it started using htmlentities
  8589. // without specifying the charset.
  8590. //
  8591. $s_value = $SubstituteFields->GetSafeFieldValue($s_name,$b_text_subs,$s_list_sep);
  8592. else
  8593. $s_value = $SubstituteFields->GetFieldValue($s_name,$s_list_sep);
  8594. $s_value = Truncate($s_value,$n_max_chars,$n_max_lines);
  8595. if ($b_html && $b_insert_br)
  8596. //
  8597. // Insert HTML line breaks before newlines.
  8598. //
  8599. $s_value = nl2br($s_value);
  8600. }
  8601. elseif (isset($SPECIAL_VALUES[$s_name]))
  8602. {
  8603. $s_value = $b_html ?
  8604. htmlspecialchars((string) $SPECIAL_VALUES[$s_name]) :
  8605. (string) $SPECIAL_VALUES[$s_name];
  8606. $s_value = Truncate($s_value,$n_max_chars,$n_max_lines);
  8607. }
  8608. elseif (isset($s_repl))
  8609. //
  8610. // If a replacement value has been specified use it, and
  8611. // don't call htmlspecialchars. This allows the use
  8612. // of HTML tags in a replacement string.
  8613. //
  8614. $s_value = $s_repl;
  8615. else
  8616. $s_value = "";
  8617. return ($s_value);
  8618. }
  8619. //
  8620. // Callback function for preg_replace_callback. Returns the value
  8621. // of the matched variable name.
  8622. // Variables are searched for in the global $SubstituteFields.
  8623. // If no such variable exists, an error is reported or an special
  8624. // replacement string is used.
  8625. // Errors are stored in the global $aSubstituteErrors.
  8626. //
  8627. function SubstituteValue($a_matches)
  8628. {
  8629. global $sSubstituteMissing;
  8630. return (SubstituteValueWorker($a_matches,$sSubstituteMissing));
  8631. }
  8632. //
  8633. // Callback function for preg_replace_callback. Returns the value
  8634. // of the matched variable name.
  8635. // Variables are searched for in the global $SubstituteFields.
  8636. // If no such variable exists, an error is reported or an special
  8637. // replacement string is used.
  8638. // Errors are stored in the global $aSubstituteErrors.
  8639. //
  8640. function SubstituteValuePlain($a_matches)
  8641. {
  8642. global $sSubstituteMissing;
  8643. return (SubstituteValueWorker($a_matches,$sSubstituteMissing,false));
  8644. }
  8645. //
  8646. // Callback function for preg_replace_callback. Returns the value
  8647. // of the matched variable name.
  8648. // Variables are searched for in the global $SubstituteFields.
  8649. // If no such variable exists, the empty string is substituted.
  8650. // Errors are stored in the global $aSubstituteErrors.
  8651. //
  8652. function SubstituteValueForPage($a_matches)
  8653. {
  8654. return (SubstituteValueWorker($a_matches,""));
  8655. }
  8656. //
  8657. // Callback function for preg_replace_callback. Returns
  8658. // exactly what was matched.
  8659. //
  8660. function SubstituteValueDummy($a_matches)
  8661. {
  8662. return ($a_matches[0]);
  8663. }
  8664. //
  8665. // Process the given HTML template and fill the fields.
  8666. //
  8667. function DoProcessTemplate($s_dir,$s_url,$s_template,&$a_lines,
  8668. $a_values,$s_missing,$s_subs_func)
  8669. {
  8670. global $aSubstituteErrors,$SubstituteFields,$sSubstituteMissing;
  8671. if (($a_template_lines = LoadTemplate($s_template,$s_dir,
  8672. $s_url,true)) === false)
  8673. return (false);
  8674. FMDebug("Template '$s_template' contains ".count($a_template_lines)." lines");
  8675. $b_ok = true;
  8676. //
  8677. // initialize the errors list
  8678. //
  8679. $aSubstituteErrors = array();
  8680. //
  8681. // initialize the values
  8682. //
  8683. $SubstituteFields = new FieldManager($a_values,array());
  8684. $sSubstituteMissing = $s_missing;
  8685. foreach ($a_template_lines as $s_line)
  8686. {
  8687. //
  8688. // search for words in these forms:
  8689. // $word
  8690. // ${word:options}
  8691. // where word begins with an alphabetic character and
  8692. // consists of alphanumeric and underscore
  8693. //
  8694. $a_lines[] = preg_replace_callback('/\$[a-z][a-z0-9_]*|\$\{[a-z][a-z0-9_]*(:[^\}]*)*\}/i',
  8695. $s_subs_func,$s_line);
  8696. }
  8697. FMDebug("DoProcessTemplate error count=".count($aSubstituteErrors));
  8698. if (count($aSubstituteErrors) != 0)
  8699. {
  8700. SendAlert(GetMessage(MSG_TEMPLATE_ERRORS,array("NAME"=>$s_template)).
  8701. implode("\n",$aSubstituteErrors));
  8702. $b_ok = false;
  8703. }
  8704. global $FMCTemplProc;
  8705. //
  8706. // note that it's possible for an old version of FormMail Computation
  8707. // module to get loaded which doesn't provide FMCTemplProc
  8708. //
  8709. if ($b_ok && ADVANCED_TEMPLATES && isset($FMCTemplProc))
  8710. {
  8711. $s_buf = implode("\n",$a_lines);
  8712. /*
  8713. * Look for a string that means we can skip advanced template
  8714. * processing on this template. The string is "FormMail-Basic-Template".
  8715. */
  8716. if (strpos($s_buf,"FormMail-Basic-Template") === FALSE)
  8717. {
  8718. $a_mesgs = array();
  8719. /*foreach ($a_lines as $i_lno=>$s_line)
  8720. if (strpos($s_line,"\n") !== false)
  8721. SendAlert("Line $i_lno has a newline");*/
  8722. set_time_limit(60);
  8723. if (($m_result = $FMCTemplProc->Process($s_buf,$a_mesgs)) === false)
  8724. {
  8725. $s_msgs = "\n";
  8726. foreach ($a_mesgs as $a_msg)
  8727. {
  8728. $s_msgs .= "Line ".$a_msg["LINE"];
  8729. $s_msgs .= ", position ".$a_msg["CHAR"].": ";
  8730. $s_msgs .= $a_msg["MSG"]."\n";
  8731. }
  8732. Error("fmadvtemplates",GetMessage(MSG_TEMPL_PROC,
  8733. array("ERRORS"=>$s_msgs)),false,false);
  8734. $b_ok = false;
  8735. }
  8736. else
  8737. {
  8738. /*foreach ($m_result as $i_lno=>$s_line)
  8739. if (($nn = substr_count($s_line,"\n")) > 1)
  8740. SendAlert("Result line $i_lno has $nn newlines");*/
  8741. //
  8742. // strip the new lines
  8743. //
  8744. $a_lines = explode("\n",implode("",$m_result));
  8745. }
  8746. $a_alerts = $FMCTemplProc->GetAlerts();
  8747. if (count($a_alerts) > 0)
  8748. SendAlert(GetMessage(MSG_TEMPL_ALERT,
  8749. array("ALERTS"=>implode("\n",$a_alerts))));
  8750. $a_debug = $FMCTemplProc->GetDebug();
  8751. if (count($a_debug) > 0)
  8752. SendAlert(GetMessage(MSG_TEMPL_DEBUG,
  8753. array("DEBUG"=>implode("\n",$a_debug))));
  8754. }
  8755. }
  8756. return ($b_ok);
  8757. }
  8758. //
  8759. // Process the given HTML template and fill the fields.
  8760. //
  8761. function ProcessTemplate($s_template,&$a_lines,$a_values,$s_missing = NULL,
  8762. $s_subs_func = 'SubstituteValue')
  8763. {
  8764. global $TEMPLATEURL,$TEMPLATEDIR;
  8765. if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
  8766. {
  8767. SendAlert(GetMessage(MSG_TEMPLATES));
  8768. return (false);
  8769. }
  8770. return (DoProcessTemplate($TEMPLATEDIR,$TEMPLATEURL,$s_template,$a_lines,
  8771. $a_values,$s_missing,$s_subs_func));
  8772. }
  8773. //
  8774. // Output the given HTML template after filling in the fields.
  8775. //
  8776. function OutputTemplate($s_template,$a_values)
  8777. {
  8778. $a_lines = array();
  8779. if (!ProcessTemplate($s_template,$a_lines,$a_values,"",'SubstituteValueForPage'))
  8780. Error("template_failed",GetMessage(MSG_TEMPLATE_FAILED,
  8781. array("NAME"=>$s_template)),false,false);
  8782. else
  8783. {
  8784. for ($ii = 0 ; $ii < count($a_lines) ; $ii++)
  8785. echo $a_lines[$ii]."\n";
  8786. }
  8787. }
  8788. //
  8789. // This function handles input type fields.
  8790. //
  8791. function RemoveFieldValue($s_name,$s_buf)
  8792. {
  8793. //
  8794. // we search for:
  8795. // <input ... name="thename" ... >
  8796. // and change it to:
  8797. // <!-- disabled by FormMail: input ... name="thename" ... -->
  8798. //
  8799. // handle name attribute first
  8800. $s_pat = '/<(\s*input[^>]*name="';
  8801. $s_pat .= preg_quote($s_name,"/");
  8802. $s_pat .= '"[^>]*)>';
  8803. $s_pat .= '/ims';
  8804. $s_buf = preg_replace($s_pat,'<!-- disabled by FormMail: $1 -->',$s_buf);
  8805. return ($s_buf);
  8806. }
  8807. //
  8808. // Quote special characters in a replacement expression
  8809. // for preg_replace.
  8810. //
  8811. function RegReplaceQuote($s_value)
  8812. {
  8813. return (str_replace('$','\\$',str_replace('\\','\\\\',$s_value)));
  8814. }
  8815. //
  8816. // This function handles input type "text" and "password"
  8817. //
  8818. function FixInputText($s_name,$s_value,$s_buf)
  8819. {
  8820. //
  8821. // we search for:
  8822. // <input type="text" name="thename"...
  8823. // and change it to:
  8824. // <input type="text" name="thename" value="thevalue" ...
  8825. //
  8826. // Note that the value attribute must appear *after* the
  8827. // type and name attributes.
  8828. //
  8829. //
  8830. // first strip any current value attribute for the field
  8831. //
  8832. //
  8833. // (?:) is a grouping subpattern that does no capturing
  8834. //
  8835. // handle type attribute first
  8836. $s_pat = '/(<\s*input[^>]*type="(?:text|password)"[^>]*name="';
  8837. $s_pat .= preg_quote($s_name,"/");
  8838. $s_pat .= '"[^>]*)(value="[^"]*")([^>]*?)(\s*\/\s*)?>';
  8839. $s_pat .= '/ims';
  8840. $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  8841. // handle name attribute first
  8842. $s_pat = '/(<\s*input[^>]*name="';
  8843. $s_pat .= preg_quote($s_name,"/");
  8844. $s_pat .= '"[^>]*type="(?:text|password)"[^>]*)(value="[^"]*")([^>]*?)(\s*\/\s*)?>';
  8845. $s_pat .= '/ims';
  8846. $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  8847. //
  8848. // now add in the new value
  8849. //
  8850. $s_repl = '$1 value="'.htmlspecialchars(RegReplaceQuote($s_value)).'" $2>';
  8851. // handle type attribute first
  8852. $s_pat = '/(<\s*input[^>]*type="(?:text|password)"[^>]*name="';
  8853. $s_pat .= preg_quote($s_name,"/");
  8854. $s_pat .= '"[^>]*?)(\s*\/\s*)?>';
  8855. $s_pat .= '/ims';
  8856. $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  8857. // handle name attribute first
  8858. $s_pat = '/(<\s*input[^>]*name="';
  8859. $s_pat .= preg_quote($s_name,"/");
  8860. $s_pat .= '"[^>]*type="(?:text|password)"[^>]*?)(\s*\/\s*)?>';
  8861. $s_pat .= '/ims';
  8862. $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  8863. return ($s_buf);
  8864. }
  8865. //
  8866. // This function handles textareas.
  8867. //
  8868. function FixTextArea($s_name,$s_value,$s_buf)
  8869. {
  8870. //
  8871. // we search for:
  8872. // <textarea name="thename"...>value</textarea>
  8873. // and change it to:
  8874. // <textarea name="thename"...>new value</textarea>
  8875. //
  8876. $s_pat = '/(<\s*textarea[^>]*name="';
  8877. $s_pat .= preg_quote($s_name,"/");
  8878. $s_pat .= '"[^>]*)>.*?<\s*\/\s*textarea\s*>';
  8879. $s_pat .= '/ims';
  8880. //
  8881. // we exclude the closing '>' from the match above so that
  8882. // we can put it below. We need to do this so that the replacement
  8883. // string is not faulty if the value begins with a digit:
  8884. // $19 Some Street
  8885. //
  8886. $s_repl = '$1>'.htmlspecialchars(RegReplaceQuote($s_value)).'</textarea>';
  8887. $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  8888. return ($s_buf);
  8889. }
  8890. //
  8891. // This function handles radio buttons and non-array checkboxes.
  8892. //
  8893. function FixButton($s_name,$s_value,$s_buf)
  8894. {
  8895. //
  8896. // we search for:
  8897. // <input type="radio" name="thename" value="thevalue" ...
  8898. // and change it to:
  8899. // <input type="radio" name="thename" value="thevalue" checked="checked"
  8900. //
  8901. // Note that the value attribute must appear *after* the
  8902. // type and name attributes.
  8903. //
  8904. //
  8905. // first strip any current checked attributes
  8906. //
  8907. //
  8908. // (?:) is a grouping subpattern that does no capturing
  8909. //
  8910. // handle type attribute first
  8911. // match: input tag with type 'radio' or 'checkbox' with attribute
  8912. // 'checked' or 'checked="checked"'
  8913. // <A NAME="PatternInfo">
  8914. // [^>]*?[^"\w] matches up to a word boundary starting with
  8915. // 'checked' but not '"checked'
  8916. // (="checked"|(?=[^"\w]))? this matches:
  8917. // nothing
  8918. // ="checked"
  8919. // any character except a word character or " (without
  8920. // consuming it)
  8921. //
  8922. $s_pat = '/(<\s*input[^>]*type="(?:radio|checkbox)"[^>]*name="';
  8923. $s_pat .= preg_quote($s_name,"/");
  8924. $s_pat .= '"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  8925. $s_pat .= '/ims';
  8926. $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  8927. // handle name attribute first
  8928. $s_pat = '/(<\s*input[^>]*name="';
  8929. $s_pat .= preg_quote($s_name,"/");
  8930. $s_pat .= '"[^>]*type="(?:radio|checkbox)"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  8931. $s_pat .= '/ims';
  8932. $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  8933. // handle type attribute first
  8934. $s_pat = '/(<\s*input[^>]*type="(?:radio|checkbox)"[^>]*name="';
  8935. $s_pat .= preg_quote($s_name,"/");
  8936. $s_pat .= '"[^>]*value="';
  8937. $s_pat .= preg_quote($s_value,"/");
  8938. $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  8939. $s_pat .= '/ims';
  8940. $s_buf = preg_replace($s_pat,'$1$2 checked="checked" $3>',$s_buf);
  8941. // handle name attribute first
  8942. $s_pat = '/(<\s*input[^>]*name="';
  8943. $s_pat .= preg_quote($s_name,"/");
  8944. $s_pat .= '"[^>]*type="(?:radio|checkbox)"[^>]*value="';
  8945. $s_pat .= preg_quote($s_value,"/");
  8946. $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  8947. $s_pat .= '/ims';
  8948. $s_buf = preg_replace($s_pat,'$1$2 checked="checked" $3>',$s_buf);
  8949. return ($s_buf);
  8950. }
  8951. //
  8952. // This function handles checkboxes as an array of values.
  8953. //
  8954. function FixCheckboxes($s_name,$a_values,$s_buf)
  8955. {
  8956. //global $aDebug;
  8957. //
  8958. // we search for:
  8959. // <input type="checkbox" name="thename" value="thevalue" ...
  8960. // and change it to:
  8961. // <input type="checkbox" name="thename" value="thevalue" checked
  8962. //
  8963. // Note that the value attribute must appear *after* the
  8964. // type and name attributes.
  8965. //
  8966. //
  8967. // first strip any current checked attributes
  8968. //
  8969. //$aDebug[] = "FixCheckboxes: Name='$s_name'";
  8970. // handle type attribute first
  8971. // see <A HREF="fmbadhandler.php#PatternInfo">
  8972. $s_pat = '/(<\s*input[^>]*type="checkbox"[^>]*name="';
  8973. $s_pat .= preg_quote($s_name,"/");
  8974. $s_pat .= '\[]"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  8975. $s_pat .= '/ims';
  8976. $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  8977. // handle name attribute first
  8978. $s_pat = '/(<\s*input[^>]*name="';
  8979. $s_pat .= preg_quote($s_name,"/");
  8980. $s_pat .= '\[]"[^>]*type="checkbox"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  8981. $s_pat .= '/ims';
  8982. $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  8983. foreach ($a_values as $s_value)
  8984. {
  8985. // handle type attribute first
  8986. $s_pat = '/(<\s*input[^>]*type="checkbox"[^>]*name="';
  8987. $s_pat .= preg_quote($s_name,"/");
  8988. $s_pat .= '\[\]"[^>]*value="';
  8989. $s_pat .= preg_quote($s_value,"/");
  8990. $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  8991. $s_pat .= '/ims';
  8992. $s_buf = preg_replace($s_pat,'$1$2 checked="checked"$3>',$s_buf);
  8993. //$aDebug[] = "Name='$s_name', pat='$s_pat'";
  8994. // handle name attribute first
  8995. $s_pat = '/(<\s*input[^>]*name="';
  8996. $s_pat .= preg_quote($s_name,"/");
  8997. $s_pat .= '\[\]"[^>]*type="checkbox"[^>]*value="';
  8998. $s_pat .= preg_quote($s_value,"/");
  8999. $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
  9000. $s_pat .= '/ims';
  9001. $s_buf = preg_replace($s_pat,'$1$2 checked="checked">',$s_buf);
  9002. }
  9003. return ($s_buf);
  9004. }
  9005. //
  9006. // This function handles selects.
  9007. //
  9008. function FixSelect($s_name,$s_value,$s_buf)
  9009. {
  9010. //
  9011. // we search for:
  9012. // <select name="thename"...>
  9013. // <option value="thevalue">...</option>
  9014. // </select>
  9015. //
  9016. $s_pat = '/(<\s*select[^>]*name="';
  9017. $s_pat .= preg_quote($s_name,"/");
  9018. $s_pat .= '".*?<\s*option[^>]*value="';
  9019. $s_pat .= preg_quote($s_value,"/");
  9020. $s_pat .= '"[^>]*)>';
  9021. $s_pat .= '/ims';
  9022. $s_repl = '$1 selected="selected">';
  9023. // echo "<p>pat: ".htmlspecialchars($s_pat);
  9024. $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  9025. return ($s_buf);
  9026. }
  9027. //
  9028. // This function handles multiple selects.
  9029. //
  9030. function FixMultiSelect($s_name,$a_values,$s_buf)
  9031. {
  9032. //
  9033. // we search for:
  9034. // <select name="thename"...>
  9035. // <option value="thevalue">...</option>
  9036. // </select>
  9037. //
  9038. foreach ($a_values as $s_value)
  9039. {
  9040. $s_pat = '/(<\s*select[^>]*name="';
  9041. $s_pat .= preg_quote($s_name,"/");
  9042. $s_pat .= '\[\]".*?<\s*option[^>]*value="';
  9043. $s_pat .= preg_quote($s_value,"/");
  9044. $s_pat .= '"[^>]*)>';
  9045. $s_pat .= '/ims';
  9046. $s_repl = '$1 selected="selected">';
  9047. // echo "<p>pat: ".htmlspecialchars($s_pat);
  9048. $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
  9049. }
  9050. return ($s_buf);
  9051. }
  9052. //
  9053. // This function unchecks all checkboxes and select options.
  9054. //
  9055. function UnCheckStuff($s_buf)
  9056. {
  9057. global $php_errormsg;
  9058. //
  9059. // we search for:
  9060. // <input type="checkbox" ... checked
  9061. // and remove "checked" (checked="checked" is OK too)
  9062. //
  9063. // Note that the check attribute must appear *after* the
  9064. // type attribute.
  9065. // see <A HREF="fmbadhandler.php#PatternInfo">
  9066. //
  9067. $s_pat = '/(<\s*input[^>]*type="checkbox"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
  9068. $s_pat .= '/ims';
  9069. $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
  9070. //
  9071. // we search for:
  9072. // <option... selected
  9073. // and remove "selected" (selected="selected" is OK too)
  9074. // see <A HREF="fmbadhandler.php#PatternInfo">
  9075. //
  9076. $s_pat = '/(<\s*option[^>]*?[^"\w])selected(="selected"|(?=[^"\w]))?([^>]*)>';
  9077. $s_pat .= '/ims';
  9078. $s_buf = preg_replace($s_pat,'$1$3>',$s_buf);
  9079. return ($s_buf);
  9080. }
  9081. //
  9082. // Add the user agent to the url as a parameter called USER_AGENT.
  9083. // This allows dynamic web sites to know what the user's browser is.
  9084. //
  9085. function AddUserAgent($s_url)
  9086. {
  9087. global $aServerVars,$aGetVars;
  9088. //
  9089. // check if the USER_AGENT has been passed as a URL parameter,
  9090. // if so, use it
  9091. //
  9092. $s_agent = "";
  9093. if (isset($aGetVars['USER_AGENT']) && $aGetVars['USER_AGENT'] !== "")
  9094. {
  9095. $s_agent = $aGetVars['USER_AGENT'];
  9096. //
  9097. // check for URL encoding, and if not, then encode it
  9098. //
  9099. if (!IsURLEncoded($s_agent))
  9100. $s_agent = urlencode($s_agent);
  9101. }
  9102. elseif (isset($aServerVars['HTTP_USER_AGENT']))
  9103. $s_agent = urlencode($aServerVars['HTTP_USER_AGENT']);
  9104. if ($s_agent !== "")
  9105. return (AddURLParams($s_url,"USER_AGENT=$s_agent",false));
  9106. else
  9107. return ($s_url);
  9108. }
  9109. //
  9110. // Try to determine if the given string is already URL-encoded
  9111. //
  9112. function IsURLEncoded($s_str)
  9113. {
  9114. //
  9115. // the only non-alphanumeric characters we'd expect
  9116. // to see are defined as safe or extra in RFC 1738:
  9117. // safe = "$" | "-" | "_" | "." | "+"
  9118. // extra = "!" | "*" | "'" | "(" | ")" | ","
  9119. // plus the encoding character %
  9120. //
  9121. if (preg_match('/[^a-z0-9$_.+!*\'(),%-]/i',$s_str,$a_matches))
  9122. {
  9123. FMDebug("IsURLEncoded: '$s_str' matched '".$a_matches[0]."' and is therefore not URL-encoded");
  9124. return (false);
  9125. }
  9126. return (true);
  9127. }
  9128. //
  9129. // Sets previous values in a form.
  9130. //
  9131. function SetPreviousValues($s_form_buf,$a_values,$a_strip = array())
  9132. {
  9133. //
  9134. // Uncheck any checkboxes and select options
  9135. //
  9136. $s_form_buf = UnCheckStuff($s_form_buf);
  9137. foreach ($a_values as $s_name=>$m_value)
  9138. {
  9139. if (is_array($m_value))
  9140. {
  9141. //
  9142. // note that if no values are selected for a field,
  9143. // then we will never get here for that field
  9144. //
  9145. $s_form_buf = FixCheckboxes($s_name,$m_value,$s_form_buf);
  9146. $s_form_buf = FixMultiSelect($s_name,$m_value,$s_form_buf);
  9147. }
  9148. else
  9149. {
  9150. //
  9151. // Fix the field if it's an input type "text" or "password".
  9152. //
  9153. $s_form_buf = FixInputText($s_name,$m_value,$s_form_buf);
  9154. //
  9155. // Fix the field if it's radio button.
  9156. //
  9157. $s_form_buf = FixButton($s_name,$m_value,$s_form_buf);
  9158. //
  9159. // Fix the field if it's a "textarea".
  9160. //
  9161. $s_form_buf = FixTextArea($s_name,$m_value,$s_form_buf);
  9162. //
  9163. // Fix the field if it's a "select".
  9164. //
  9165. $s_form_buf = FixSelect($s_name,$m_value,$s_form_buf);
  9166. }
  9167. }
  9168. //
  9169. // Now strip particular field values.
  9170. //
  9171. foreach ($a_strip as $s_name)
  9172. $s_form_buf = RemoveFieldValue($s_name,$s_form_buf);
  9173. return ($s_form_buf);
  9174. }
  9175. //
  9176. // Open a URL, do value substitutions, and send to browser.
  9177. // The a_strip array provides a list of fields (usually
  9178. // hidden fields) to remove from the form (their values are
  9179. // set to empty).
  9180. //
  9181. function ProcessReturnToForm($s_url,$a_values,$a_strip = array())
  9182. {
  9183. global $php_errormsg;
  9184. //
  9185. // read the original form, and modify it to provide values
  9186. // for the fields
  9187. //
  9188. if (!CheckValidURL($s_url))
  9189. Error("invalid_url",GetMessage(MSG_RETURN_URL_INVALID,
  9190. array("URL"=>$s_url)),false,false);
  9191. $s_form_url = AddUserAgent($s_url);
  9192. $s_error = "";
  9193. $s_form_buf = GetURL($s_form_url,$s_error);
  9194. if ($s_form_buf === false)
  9195. Error("invalid_url",GetMessage(MSG_OPEN_URL,
  9196. array("URL"=>$s_form_url,
  9197. "ERROR"=>$s_error.": ".(isset($php_errormsg) ?
  9198. $php_errormsg : ""))),false,false);
  9199. //
  9200. // Next, we replace or set actual field values.
  9201. //
  9202. echo SetPreviousValues($s_form_buf,$a_values,$a_strip);
  9203. }
  9204. //
  9205. // To return the URL for returning to a particular multi-page form URL.
  9206. //
  9207. function GetReturnLink($s_this_script,$i_form_index)
  9208. {
  9209. if (!CheckValidURL($s_this_script))
  9210. Error("not_valid_url",GetMessage(MSG_RETURN_URL_INVALID,
  9211. array("URL"=>$s_this_script)),false,false);
  9212. $a_params = array();
  9213. $a_params[] = "return=$i_form_index";
  9214. if (isset($aServerVars["QUERY_STRING"]))
  9215. $a_params[] = $aServerVars["QUERY_STRING"];
  9216. $a_params[] = session_name()."=".session_id();
  9217. return (AddURLParams($s_this_script,$a_params));
  9218. }
  9219. //
  9220. // Process a multi-page form template.
  9221. //
  9222. function ProcessMultiFormTemplate($s_template,$a_values,&$a_lines)
  9223. {
  9224. global $MULTIFORMURL,$MULTIFORMDIR,$SPECIAL_VALUES;
  9225. if (empty($MULTIFORMDIR) && empty($MULTIFORMURL))
  9226. {
  9227. SendAlert(GetMessage(MSG_MULTIFORM));
  9228. return (false);
  9229. }
  9230. //
  9231. // create the "this_form_url" field
  9232. //
  9233. $i_index = GetSession("FormIndex");
  9234. $a_list = GetSession("FormList");
  9235. $a_values["this_form_url"] = $a_list[$i_index]["URL"];
  9236. //
  9237. // get the persistent file fields
  9238. //
  9239. $a_values = GetSavedFileNames($a_values);
  9240. //$a_values["prev_form"] = GetReturnLink($SPECIAL_VALUES["this_form"]);
  9241. return (DoProcessTemplate($MULTIFORMDIR,$MULTIFORMURL,$s_template,$a_lines,
  9242. $a_values,"",'SubstituteValueForPage'));
  9243. }
  9244. //
  9245. // Output the multi-form template after filling in the fields.
  9246. //
  9247. function OutputMultiFormTemplate($s_template,$a_values)
  9248. {
  9249. $a_lines = array();
  9250. if (!ProcessMultiFormTemplate($s_template,$a_values,$a_lines))
  9251. Error("multi_form_failed",GetMessage(MSG_MULTIFORM_FAILED,
  9252. array("NAME"=>$s_template)),false,false);
  9253. else
  9254. {
  9255. $n_lines = count($a_lines);
  9256. $s_buf = "";
  9257. for ($ii = 0 ; $ii < $n_lines ; $ii++)
  9258. {
  9259. $s_buf .= $a_lines[$ii]."\n";
  9260. unset($a_lines[$ii]); // free memory (hopefully)
  9261. }
  9262. unset($a_lines); // free memory (hopefully)
  9263. if (IsSetSession("FormKeep"))
  9264. //
  9265. // put in any values that are being forward-remembered
  9266. //
  9267. echo SetPreviousValues($s_buf,GetSession("FormKeep"));
  9268. else
  9269. echo $s_buf;
  9270. }
  9271. }
  9272. //
  9273. // Insert a preamble into a MIME message.
  9274. //
  9275. function MimePreamble(&$a_lines,$a_mesg = array())
  9276. {
  9277. $a_preamble = explode("\n",GetMessage(MSG_MIME_PREAMBLE));
  9278. foreach ($a_preamble as $s_line)
  9279. $a_lines[] = $s_line.HEAD_CRLF;
  9280. $a_lines[] = HEAD_CRLF; // blank line
  9281. $b_need_blank = false;
  9282. foreach ($a_mesg as $s_line)
  9283. {
  9284. $a_lines[] = $s_line.HEAD_CRLF;
  9285. if (!empty($s_line))
  9286. $b_need_blank = true;
  9287. }
  9288. if ($b_need_blank)
  9289. $a_lines[] = HEAD_CRLF; // blank line
  9290. }
  9291. //
  9292. // Create the HTML mail
  9293. //
  9294. function HTMLMail(&$a_lines,&$a_headers,$s_body,$s_template,$s_missing,$s_filter,
  9295. $s_boundary,$a_raw_fields,$b_no_plain,$b_process_template)
  9296. {
  9297. $s_charset = GetMailOption("CharSet");
  9298. if (!isset($s_charset))
  9299. $s_charset = "ISO-8859-1";
  9300. if ($b_no_plain)
  9301. {
  9302. $b_multi = false;
  9303. //
  9304. // don't provide a plain text version - just the HTML
  9305. //
  9306. $a_headers['Content-Type'] = SafeHeader("text/html; charset=$s_charset");
  9307. }
  9308. else
  9309. {
  9310. $b_multi = true;
  9311. $a_headers['Content-Type'] = "multipart/alternative; boundary=\"$s_boundary\"";
  9312. $a_pre_lines = explode("\n",GetMessage(MSG_MIME_HTML,
  9313. array("NAME"=>$s_template)));
  9314. MimePreamble($a_lines,$a_pre_lines);
  9315. //
  9316. // first part - the text version only
  9317. //
  9318. $a_lines[] = "--$s_boundary".HEAD_CRLF;
  9319. $a_lines[] = "Content-Type: text/plain; charset=$s_charset".HEAD_CRLF;
  9320. $a_lines[] = HEAD_CRLF; // blank line
  9321. //
  9322. // treat the body like one line, even though it isn't
  9323. //
  9324. $a_lines[] = $s_body;
  9325. $a_lines[] = HEAD_CRLF; // blank line
  9326. //
  9327. // second part - the HTML version
  9328. //
  9329. $a_lines[] = "--$s_boundary".HEAD_CRLF;
  9330. $a_lines[] = "Content-Type: text/html; charset=$s_charset".HEAD_CRLF;
  9331. $a_lines[] = HEAD_CRLF; // blank line
  9332. }
  9333. $a_html_lines = array();
  9334. if (!$b_process_template)
  9335. {
  9336. if (!ProcessTemplate($s_template,$a_html_lines,$a_raw_fields,NULL,'SubstituteValueDummy'))
  9337. return (false);
  9338. }
  9339. elseif (!ProcessTemplate($s_template,$a_html_lines,$a_raw_fields,$s_missing))
  9340. return (false);
  9341. if (!empty($s_filter))
  9342. //
  9343. // treat the data like one line, even though it isn't
  9344. //
  9345. $a_lines[] = Filter($s_filter,$a_html_lines);
  9346. else
  9347. foreach ($a_html_lines as $s_line)
  9348. $a_lines[] = $s_line;
  9349. if ($b_multi)
  9350. {
  9351. //
  9352. // end
  9353. //
  9354. $a_lines[] = "--$s_boundary--".HEAD_CRLF;
  9355. $a_lines[] = HEAD_CRLF; // blank line
  9356. }
  9357. return (true);
  9358. }
  9359. //
  9360. // Add the contents of a file in base64 encoding.
  9361. //
  9362. function AddFile(&$a_lines,$s_file_name,$i_file_size,$b_remove = true)
  9363. {
  9364. global $php_errormsg;
  9365. @ $fp = fopen($s_file_name,"rb");
  9366. if ($fp === false)
  9367. {
  9368. SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_file_name,
  9369. "TYPE"=>"attachment",
  9370. "ERROR"=>CheckString($php_errormsg))));
  9371. return (false);
  9372. }
  9373. //
  9374. // PHP under IIS has problems with the filesize function when
  9375. // the file is on another drive. So, we replaced a call
  9376. // to filesize with the $i_file_size parameter (this occurred
  9377. // in version 3.01).
  9378. //
  9379. $s_contents = fread($fp,$i_file_size);
  9380. //
  9381. // treat as a single line, even though it isn't
  9382. //
  9383. $a_lines[] = chunk_split(base64_encode($s_contents));
  9384. fclose($fp);
  9385. if ($b_remove)
  9386. @unlink($s_file_name);
  9387. return (true);
  9388. }
  9389. //
  9390. // Add the contents of a string in base64 encoding.
  9391. //
  9392. function AddData(&$a_lines,$s_data)
  9393. {
  9394. //
  9395. // treat as a single line, even though it isn't
  9396. //
  9397. $a_lines[] = chunk_split(base64_encode($s_data));
  9398. return (true);
  9399. }
  9400. //
  9401. // Check if a file is a valid uploaded file.
  9402. //
  9403. function IsUploadedFile($a_file_spec)
  9404. {
  9405. //
  9406. // $a_file_spec["moved"] is our own internal flag to say we've
  9407. // saved the file
  9408. //
  9409. if (isset($a_file_spec["moved"]) && $a_file_spec["moved"])
  9410. return (true);
  9411. return (is_uploaded_file($a_file_spec["tmp_name"]));
  9412. }
  9413. //
  9414. // Save an uploaded file to the repository directory.
  9415. //
  9416. function SaveFileInRepository(&$a_file_spec)
  9417. {
  9418. global $php_errormsg,$FILE_REPOSITORY;
  9419. //
  9420. // if a replacement name has been specified, use that, otherwise
  9421. // use the original name
  9422. //
  9423. if (isset($a_file_spec["new_name"]))
  9424. $s_file_name = basename($a_file_spec["new_name"]);
  9425. else
  9426. $s_file_name = basename($a_file_spec["name"]);
  9427. $s_dest = $FILE_REPOSITORY."/".$s_file_name;
  9428. $b_ok = true;
  9429. $s_error = "";
  9430. if (isset($a_file_spec["saved_as"]) && !empty($a_file_spec["saved_as"]))
  9431. {
  9432. FMDebug("SaveFileInRepository: saved_as");
  9433. $s_srce = $a_file_spec["saved_as"];
  9434. }
  9435. else
  9436. $s_srce = $a_file_spec["tmp_name"];
  9437. FMDebug("SaveFileInRepository: $s_srce");
  9438. if (!FILE_OVERWRITE)
  9439. {
  9440. clearstatcache();
  9441. if (@file_exists($s_dest))
  9442. {
  9443. $b_ok = false;
  9444. $s_error = GetMessage(MSG_SAVE_FILE_EXISTS,array("FILE"=>$s_dest));
  9445. }
  9446. }
  9447. if (MAX_FILE_UPLOAD_SIZE != 0 &&
  9448. $a_file_spec["size"] > MAX_FILE_UPLOAD_SIZE*1024)
  9449. //
  9450. // this exits
  9451. //
  9452. UserError("upload_size",GetMessage(MSG_FILE_UPLOAD_SIZE,
  9453. array("NAME"=>$a_file_spec["name"],
  9454. "SIZE"=>$a_file_spec["size"],
  9455. "MAX"=>MAX_FILE_UPLOAD_SIZE)));
  9456. if ($b_ok)
  9457. {
  9458. if (isset($a_file_spec["saved_as"]) && !empty($a_file_spec["saved_as"]))
  9459. {
  9460. if (!copy($s_srce,$s_dest) || !@unlink($s_srce))
  9461. $b_ok = false;
  9462. }
  9463. else
  9464. {
  9465. if (!move_uploaded_file($s_srce,$s_dest))
  9466. $b_ok = false;
  9467. }
  9468. if ($b_ok)
  9469. {
  9470. //
  9471. // Flag to say it's been put in the repository.
  9472. //
  9473. $a_file_spec["in_repository"] = true;
  9474. //
  9475. // Its new location
  9476. //
  9477. $a_file_spec["saved_as"] = $s_dest;
  9478. //
  9479. // Now that the file has been saved, "is_uploaded_file"
  9480. // will return false. So, we create a flag to say it was
  9481. // valid.
  9482. //
  9483. $a_file_spec["moved"] = true;
  9484. }
  9485. else
  9486. $s_error = $php_errormsg;
  9487. }
  9488. if (!$b_ok)
  9489. {
  9490. SendAlert(GetMessage(MSG_SAVE_FILE,array(
  9491. "FILE"=>$s_srce,
  9492. "DEST"=>$s_dest,
  9493. "ERR"=>$s_error)));
  9494. return (false);
  9495. }
  9496. //
  9497. // ignore chmod fails (other than reporting them)
  9498. //
  9499. if (FILE_MODE != 0 && !chmod($s_dest,FILE_MODE))
  9500. SendAlert(GetMessage(MSG_CHMOD,array(
  9501. "FILE"=>$s_dest,
  9502. "MODE"=>FILE_MODE,
  9503. "ERR"=>$s_error)));
  9504. return (true);
  9505. }
  9506. //
  9507. // Save all uploaded files to the repository directory.
  9508. //
  9509. function SaveAllFilesToRepository()
  9510. {
  9511. global $aFileVars,$FILE_REPOSITORY;
  9512. if (!FILEUPLOADS || $FILE_REPOSITORY === "")
  9513. //
  9514. // nothing to do
  9515. //
  9516. return (true);
  9517. foreach ($aFileVars as $m_file_key=>$a_upload)
  9518. {
  9519. //
  9520. // One customer reported:
  9521. // Possible file upload attack detected: name='' temp name='none'
  9522. // on PHP 4.1.2 on RAQ4.
  9523. // So, we now also test for "name".
  9524. //
  9525. if (!isset($a_upload["tmp_name"]) || empty($a_upload["tmp_name"]) ||
  9526. !isset($a_upload["name"]) || empty($a_upload["name"]))
  9527. continue;
  9528. if (isset($a_upload["in_repository"]) && $a_upload["in_repository"])
  9529. //
  9530. // already saved
  9531. //
  9532. continue;
  9533. if (!IsUploadedFile($a_upload))
  9534. {
  9535. SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
  9536. array("NAME"=>$a_upload["name"],
  9537. "TEMP"=>$a_upload["tmp_name"],
  9538. "FLD"=>$m_file_key)));
  9539. continue;
  9540. }
  9541. if (!SaveFileInRepository($aFileVars[$m_file_key]))
  9542. return (false);
  9543. //
  9544. // Now the file has been saved in the repository, make
  9545. // the field persistent through all further processing
  9546. // (e.g. all movements in a multi-page form)
  9547. //
  9548. if (IsSetSession("FormSavedFiles"))
  9549. $a_saved_files = GetSession("FormSavedFiles");
  9550. else
  9551. $a_saved_files = array();
  9552. $a_saved_files["repository_".$m_file_key] = $aFileVars[$m_file_key];
  9553. SetSession("FormSavedFiles",$a_saved_files);
  9554. }
  9555. return (true);
  9556. }
  9557. //
  9558. // Delete an uploaded file from the repository directory.
  9559. // For security reasons, only the field name can be used. This
  9560. // uniquely identifies an uploaded file by this form process.
  9561. //
  9562. function DeleteFileFromRepository($s_fld)
  9563. {
  9564. global $aFileVars,$FILE_REPOSITORY;
  9565. if (!FILEUPLOADS || $FILE_REPOSITORY === "")
  9566. //
  9567. // nothing to do
  9568. //
  9569. return (false);
  9570. if (($a_upload = GetFileInfo($s_fld)) === false)
  9571. return (false);
  9572. if (isset($a_upload["in_repository"]) && $a_upload["in_repository"])
  9573. {
  9574. if (isset($a_upload["saved_as"]) && !empty($a_upload["saved_as"]))
  9575. @unlink($a_upload["saved_as"]);
  9576. }
  9577. DeleteFileInfo($s_fld);
  9578. return (true);
  9579. }
  9580. //
  9581. // Save an uploaded file for later processing.
  9582. //
  9583. function SaveUploadedFile(&$a_file_spec,$s_prefix)
  9584. {
  9585. global $php_errormsg;
  9586. FMDebug("SaveUploadedFile");
  9587. $s_dest = GetScratchPadFile($s_prefix);
  9588. if (!move_uploaded_file($a_file_spec["tmp_name"],$s_dest))
  9589. {
  9590. SendAlert(GetMessage(MSG_SAVE_FILE,array(
  9591. "FILE"=>$a_file_spec["tmp_name"],
  9592. "DEST"=>$s_dest,
  9593. "ERR"=>$php_errormsg)));
  9594. return (false);
  9595. }
  9596. $a_file_spec["saved_as"] = $s_dest;
  9597. $a_file_spec["moved"] = true;
  9598. return (true);
  9599. }
  9600. //
  9601. // Remove old files from the scratchpad directory.
  9602. //
  9603. function CleanScratchPad($s_prefix = "")
  9604. {
  9605. global $lNow,$CLEANUP_TIME,$CLEANUP_CHANCE;
  9606. global $php_errormsg,$SCRATCH_PAD;
  9607. if (!isset($SCRATCH_PAD) || empty($SCRATCH_PAD))
  9608. //
  9609. // no scratchpad to cleanup!
  9610. //
  9611. return;
  9612. if ($CLEANUP_TIME <= 0)
  9613. //
  9614. // cleanup disabled
  9615. //
  9616. return;
  9617. //
  9618. // compute chance of cleanup
  9619. //
  9620. if ($CLEANUP_CHANCE < 100)
  9621. {
  9622. $i_rand = mt_rand(1,100);
  9623. if ($i_rand > $CLEANUP_CHANCE)
  9624. return;
  9625. }
  9626. if (($f_dir = @opendir($SCRATCH_PAD)) === false)
  9627. {
  9628. Error("open_scratch_pad",GetMessage(MSG_OPEN_SCRATCH_PAD,array(
  9629. "DIR"=>$SCRATCH_PAD,
  9630. "ERR"=>$php_errormsg)),false,false);
  9631. return;
  9632. }
  9633. $i_len = strlen($s_prefix);
  9634. while (($s_file = readdir($f_dir)) !== false)
  9635. {
  9636. $s_path = $SCRATCH_PAD."/".$s_file;
  9637. if (is_file($s_path) && ($i_len == 0 || substr($s_file,0,$i_len) == $s_prefix))
  9638. {
  9639. if (($a_stat = @stat($s_path)) !== false)
  9640. {
  9641. if (isset($a_stat['mtime']))
  9642. $l_time = $a_stat['mtime'];
  9643. else
  9644. $l_time = $a_stat[9];
  9645. if (($lNow - $l_time) / 60 >= $CLEANUP_TIME)
  9646. @unlink($s_path);
  9647. }
  9648. }
  9649. }
  9650. closedir($f_dir);
  9651. }
  9652. //
  9653. // Save all uploaded files for later processing.
  9654. //
  9655. function SaveAllUploadedFiles(&$a_file_vars)
  9656. {
  9657. global $php_errormsg,$SCRATCH_PAD;
  9658. $s_prefix = "UPLD";
  9659. if (!isset($SCRATCH_PAD) || empty($SCRATCH_PAD))
  9660. {
  9661. Error("need_scratch_pad",GetMessage(MSG_NEED_SCRATCH_PAD),false,false);
  9662. return (false);
  9663. }
  9664. //
  9665. // remove old uploaded files that have not been moved out.
  9666. //
  9667. CleanScratchPad($s_prefix);
  9668. foreach (array_keys($a_file_vars) as $m_file_key)
  9669. {
  9670. $a_upload = &$a_file_vars[$m_file_key];
  9671. //
  9672. // One customer reported:
  9673. // Possible file upload attack detected: name='' temp name='none'
  9674. // on PHP 4.1.2 on RAQ4.
  9675. // So, we now also test for "name".
  9676. //
  9677. if (!isset($a_upload["tmp_name"]) || empty($a_upload["tmp_name"]) ||
  9678. !isset($a_upload["name"]) || empty($a_upload["name"]))
  9679. continue;
  9680. //
  9681. // ensure we don't move the file more than once
  9682. //
  9683. if (!isset($a_upload["saved_as"]) || empty($a_upload["saved_as"]))
  9684. if (!IsUploadedFile($a_upload))
  9685. SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
  9686. array("NAME"=>$a_upload["name"],
  9687. "TEMP"=>$a_upload["tmp_name"],
  9688. "FLD"=>$m_file_key)));
  9689. elseif (!SaveUploadedFile($a_upload,$s_prefix))
  9690. return (false);
  9691. }
  9692. return (true);
  9693. }
  9694. //
  9695. // Attach a file to the body of a MIME formatted email. $a_lines is the
  9696. // current body, and is modified to include the file.
  9697. // $a_file_spec must have the following values (just like an uploaded
  9698. // file specification):
  9699. // name the name of the file
  9700. // type the mime type
  9701. // tmp_name the name of the temporary file
  9702. // size the size of the temporary file
  9703. //
  9704. // Alternatively, you supply the following instead of tmp_name and size:
  9705. // data the data to attach
  9706. //
  9707. function AttachFile(&$a_lines,$s_att_boundary,$a_file_spec,$s_charset,$b_remove = true)
  9708. {
  9709. $a_lines[] = "--$s_att_boundary".HEAD_CRLF;
  9710. //
  9711. // if a replacement name has been specified, use that, otherwise
  9712. // use the original name
  9713. //
  9714. if (isset($a_file_spec["new_name"]))
  9715. $s_file_name = $a_file_spec["new_name"];
  9716. else
  9717. $s_file_name = $a_file_spec["name"];
  9718. $s_file_name = str_replace('"','',$s_file_name);
  9719. $s_mime_type = $a_file_spec["type"];
  9720. //
  9721. // The following says that the data is encoded in
  9722. // base64 and is an attachment and that once decoded the
  9723. // character set of the decoded data is $s_charset.
  9724. // (See RFC 1521 Section 5.)
  9725. //
  9726. $a_lines[] = "Content-Type: $s_mime_type; name=\"$s_file_name\"; charset=$s_charset".HEAD_CRLF;
  9727. $a_lines[] = "Content-Transfer-Encoding: base64".HEAD_CRLF;
  9728. $a_lines[] = "Content-Disposition: attachment; filename=\"$s_file_name\"".HEAD_CRLF;
  9729. $a_lines[] = HEAD_CRLF; // blank line
  9730. if (isset($a_file_spec["tmp_name"]) && isset($a_file_spec["size"]))
  9731. {
  9732. $s_srce = $a_file_spec["tmp_name"];
  9733. //
  9734. // check if the file has been saved elsewhere
  9735. //
  9736. if (isset($a_file_spec["saved_as"]) && !empty($a_file_spec["saved_as"]))
  9737. $s_srce = $a_file_spec["saved_as"];
  9738. FMDebug("AttachFile: $s_srce");
  9739. return (AddFile($a_lines,$s_srce,$a_file_spec["size"],$b_remove));
  9740. }
  9741. if (!isset($a_file_spec["data"]))
  9742. {
  9743. SendAlert(GetMessage(MSG_ATTACH_DATA));
  9744. return (false);
  9745. }
  9746. return (AddData($a_lines,$a_file_spec["data"]));
  9747. }
  9748. //
  9749. // Reformat the email to be in MIME format.
  9750. // Process file attachments and and fill out any
  9751. // specified HTML template.
  9752. //
  9753. function MakeMimeMail(&$s_body,&$a_headers,$a_raw_fields,$s_template = "",
  9754. $s_missing = NULL,$b_no_plain = false,
  9755. $s_filter = "",$a_file_vars = array(),
  9756. $a_attach_spec = array(),$b_process_template = true)
  9757. {
  9758. global $FM_VERS,$aPHPVERSION;
  9759. global $SPECIAL_VALUES,$FILE_REPOSITORY;
  9760. $s_charset = GetMailOption("CharSet");
  9761. if (!isset($s_charset))
  9762. $s_charset = "ISO-8859-1";
  9763. $b_att = $b_html = false;
  9764. $b_got_filter = (isset($s_filter) && !empty($s_filter));
  9765. if (isset($s_template) && !empty($s_template))
  9766. {
  9767. //
  9768. // need PHP 4.0.5 for the preg_replace_callback function
  9769. //
  9770. if (!IsPHPAtLeast("4.0.5"))
  9771. {
  9772. SendAlert(GetMessage(MSG_PHP_HTML_TEMPLATES,
  9773. array("PHPVERS"=>implode(".",$aPHPVERSION))));
  9774. return (false);
  9775. }
  9776. $b_html = true;
  9777. }
  9778. if (count($a_file_vars) > 0)
  9779. {
  9780. if (!IsPHPAtLeast("4.0.3"))
  9781. {
  9782. SendAlert(GetMessage(MSG_PHP_FILE_UPLOADS,
  9783. array("PHPVERS"=>implode(".",$aPHPVERSION))));
  9784. return (false);
  9785. }
  9786. if (!FILEUPLOADS)
  9787. SendAlert(GetMessage(MSG_FILE_UPLOAD));
  9788. //
  9789. // if storing files in the server repository, don't attach
  9790. // unless the mail_options insist
  9791. //
  9792. elseif ($FILE_REPOSITORY === "" || IsMailOptionSet("AlwaysEmailFiles"))
  9793. foreach ($a_file_vars as $a_upload)
  9794. {
  9795. //
  9796. // One customer reported:
  9797. // Possible file upload attack detected: name='' temp name='none'
  9798. // on PHP 4.1.2 on RAQ4.
  9799. // So, we now also test for "name".
  9800. //
  9801. if (isset($a_upload["tmp_name"]) && !empty($a_upload["tmp_name"]) &&
  9802. isset($a_upload["name"]) && !empty($a_upload["name"]))
  9803. {
  9804. $b_att = true;
  9805. break;
  9806. }
  9807. }
  9808. }
  9809. //
  9810. // check for an internally-generated attachment
  9811. //
  9812. if (isset($a_attach_spec["Data"]))
  9813. $b_att = true;
  9814. $s_uniq = md5($s_body);
  9815. $s_body_boundary = "BODY$s_uniq";
  9816. $s_att_boundary = "PART$s_uniq";
  9817. $a_headers['MIME-Version'] = "1.0 (produced by FormMail $FM_VERS from www.tectite.com)";
  9818. //
  9819. // if the filter strips formatting, then we'll only have plain text
  9820. // to send, even after the template has been used
  9821. //
  9822. if ($b_got_filter && IsFilterAttribSet($s_filter,"Strips"))
  9823. //
  9824. // no HTML if the filter strips the formatting
  9825. //
  9826. $b_html = false;
  9827. $a_new = array();
  9828. if ($b_att)
  9829. {
  9830. $a_headers['Content-Type'] = "multipart/mixed; boundary=\"$s_att_boundary\"";
  9831. MimePreamble($a_new);
  9832. //
  9833. // add the body of the email
  9834. //
  9835. $a_new[] = "--$s_att_boundary".HEAD_CRLF;
  9836. if ($b_html)
  9837. {
  9838. $a_lines = $a_local_headers = array();
  9839. if (!HTMLMail($a_lines,$a_local_headers,$s_body,$s_template,
  9840. $s_missing,($b_got_filter) ? $s_filter : "",
  9841. $s_body_boundary,$a_raw_fields,$b_no_plain,
  9842. $b_process_template))
  9843. return (false);
  9844. $a_new = array_merge($a_new,ExpandMailHeadersArray($a_local_headers));
  9845. $a_new[] = HEAD_CRLF; // blank line after header
  9846. $a_new = array_merge($a_new,$a_lines);
  9847. }
  9848. else
  9849. {
  9850. $a_new[] = "Content-Type: text/plain; charset=$s_charset".HEAD_CRLF;
  9851. $a_new[] = HEAD_CRLF; // blank line
  9852. //
  9853. // treat the body like one line, even though it isn't
  9854. //
  9855. $a_new[] = $s_body;
  9856. }
  9857. //
  9858. // now add the attachments or save to the $FILE_REPOSITORY
  9859. //
  9860. if (FILEUPLOADS && ($FILE_REPOSITORY === "" || IsMailOptionSet("AlwaysEmailFiles")))
  9861. foreach ($a_file_vars as $m_file_key=>$a_upload)
  9862. {
  9863. //
  9864. // One customer reported:
  9865. // Possible file upload attack detected: name='' temp name='none'
  9866. // on PHP 4.1.2 on RAQ4.
  9867. // So, we now also test for "name".
  9868. //
  9869. if (!isset($a_upload["tmp_name"]) || empty($a_upload["tmp_name"]) ||
  9870. !isset($a_upload["name"]) || empty($a_upload["name"]))
  9871. continue;
  9872. if (!IsUploadedFile($a_upload))
  9873. {
  9874. SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
  9875. array("NAME"=>$a_upload["name"],
  9876. "TEMP"=>$a_upload["tmp_name"],
  9877. "FLD"=>$m_file_key)));
  9878. continue;
  9879. }
  9880. if (MAX_FILE_UPLOAD_SIZE != 0 &&
  9881. $a_upload["size"] > MAX_FILE_UPLOAD_SIZE*1024)
  9882. UserError("upload_size",GetMessage(MSG_FILE_UPLOAD_SIZE,
  9883. array("NAME"=>$a_upload["name"],
  9884. "SIZE"=>$a_upload["size"],
  9885. "MAX"=>MAX_FILE_UPLOAD_SIZE)));
  9886. if (!AttachFile($a_new,$s_att_boundary,$a_upload,$s_charset,
  9887. ($FILE_REPOSITORY === "") ? true : false))
  9888. return (false);
  9889. }
  9890. if (isset($a_attach_spec["Data"]))
  9891. {
  9892. //
  9893. // build a specification similar to a file upload
  9894. //
  9895. $a_file_spec["name"] = isset($a_attach_spec["Name"]) ?
  9896. $a_attach_spec["Name"] :
  9897. "attachment.dat";
  9898. $a_file_spec["type"] = isset($a_attach_spec["MIME"]) ?
  9899. $a_attach_spec["MIME"] :
  9900. "text/plain";
  9901. $a_file_spec["data"] = $a_attach_spec["Data"];
  9902. if (!AttachFile($a_new,$s_att_boundary,$a_file_spec,
  9903. isset($a_attach_spec["CharSet"]) ?
  9904. $a_attach_spec["CharSet"] :
  9905. $s_charset))
  9906. return (false);
  9907. }
  9908. $a_new[] = "--$s_att_boundary--".HEAD_CRLF; // the end
  9909. $a_new[] = HEAD_CRLF; // blank line
  9910. }
  9911. elseif ($b_html)
  9912. {
  9913. if (!HTMLMail($a_new,$a_headers,$s_body,$s_template,
  9914. $s_missing,($b_got_filter) ? $s_filter : "",
  9915. $s_body_boundary,$a_raw_fields,$b_no_plain,
  9916. $b_process_template))
  9917. return (false);
  9918. }
  9919. else
  9920. {
  9921. $a_headers['Content-Type'] = SafeHeader("text/plain; charset=$s_charset");
  9922. //
  9923. // treat the body like one line, even though it isn't
  9924. //
  9925. $a_new[] = $s_body;
  9926. }
  9927. $s_body = JoinLines(BODY_LF,$a_new);
  9928. return (true);
  9929. }
  9930. //
  9931. // to make a From line for the email
  9932. //
  9933. function MakeFromLine($s_email,$s_name)
  9934. {
  9935. $s_style = GetMailOption("FromLineStyle");
  9936. $s_line = "";
  9937. if (!isset($s_style))
  9938. $s_style = "";
  9939. //
  9940. // the following From line styles are in accordance with RFC 822
  9941. //
  9942. switch ($s_style)
  9943. {
  9944. default:
  9945. case "":
  9946. case "default":
  9947. case "AddrSpecName":
  9948. //
  9949. // this is the original From line style that FormMail produced
  9950. // e.g.
  9951. // jack@nowhere.com (Jack Smith)
  9952. // this is an addr-spec with a trailing comment with the name
  9953. //
  9954. if (!empty($s_email))
  9955. $s_line .= SafeHeaderEmail($s_email)." ";
  9956. if (!empty($s_name))
  9957. $s_line .= "(".SafeHeaderComment(EncodeHeaderText($s_name)).")";
  9958. break;
  9959. case "NameAddrSpec":
  9960. //
  9961. // email address as an addr-spec preceded by a comment with the name
  9962. // e.g.
  9963. // (Jack Smith) jack@nowhere.com
  9964. //
  9965. if (!empty($s_name))
  9966. $s_line .= "(".SafeHeaderComment(EncodeHeaderText($s_name)).") ";
  9967. if (!empty($s_email))
  9968. $s_line .= SafeHeaderEmail($s_email);
  9969. break;
  9970. case "RouteAddr":
  9971. //
  9972. // just the email address as a route-addr
  9973. // e.g.
  9974. // <jack@nowhere.com>
  9975. //
  9976. if (!empty($s_email))
  9977. $s_line .= "<".SafeHeaderEmail($s_email).">";
  9978. break;
  9979. case "QuotedNameRouteAddr":
  9980. //
  9981. // email address as a route-addr preceded
  9982. // by the name of the user as a quoted string
  9983. // e.g.
  9984. // "Jack Smith" <jack@nowhere.com>
  9985. //
  9986. if (!empty($s_name))
  9987. $s_line .= '"'.SafeHeaderQString(EncodeHeaderText($s_name)).'" ';
  9988. if (!empty($s_email))
  9989. $s_line .= "<".SafeHeaderEmail($s_email).">";
  9990. break;
  9991. case "NameRouteAddr":
  9992. //
  9993. // email address as a route-addr preceded
  9994. // by the name of the user as words
  9995. // e.g.
  9996. // Jack Smith <jack@nowhere.com>
  9997. //
  9998. if (!empty($s_name))
  9999. $s_line .= SafeHeaderWords(EncodeHeaderText($s_name)).' ';
  10000. if (!empty($s_email))
  10001. $s_line .= "<".SafeHeaderEmail($s_email).">";
  10002. break;
  10003. }
  10004. return ($s_line);
  10005. }
  10006. //
  10007. // Return two sets of plain text output: the filtered fields and the
  10008. // non-filtered fields.
  10009. //
  10010. function GetFilteredOutput($a_fld_order,$a_clean_fields,$s_filter,$a_filter_list)
  10011. {
  10012. //
  10013. // find the non-filtered fields and make unfiltered text from them
  10014. //
  10015. $a_unfiltered_list = array();
  10016. $n_flds = count($a_fld_order);
  10017. for ($ii = 0 ; $ii < $n_flds ; $ii++)
  10018. if (!in_array($a_fld_order[$ii],$a_filter_list))
  10019. $a_unfiltered_list[] = $a_fld_order[$ii];
  10020. $s_unfiltered_results = MakeFieldOutput($a_unfiltered_list,$a_clean_fields);
  10021. //
  10022. // filter the specified fields only
  10023. //
  10024. $s_filtered_results = MakeFieldOutput($a_filter_list,$a_clean_fields);
  10025. $s_filtered_results = Filter($s_filter,$s_filtered_results);
  10026. return (array($s_unfiltered_results,$s_filtered_results));
  10027. }
  10028. //
  10029. // Make a plain text email body
  10030. //
  10031. function MakePlainEmail($a_fld_order,$a_clean_fields,
  10032. $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,$a_filter_list)
  10033. {
  10034. global $SPECIAL_VALUES,$aPHPVERSION;
  10035. $s_unfiltered_results = $s_filtered_results = "";
  10036. $b_got_filter = (isset($s_filter) && !empty($s_filter));
  10037. if ($b_got_filter)
  10038. if (isset($a_filter_list) && count($a_filter_list) > 0)
  10039. $b_limited_filter = true;
  10040. else
  10041. $b_limited_filter = false;
  10042. $b_used_template = false;
  10043. if (IsMailOptionSet("PlainTemplate"))
  10044. {
  10045. //
  10046. // need PHP 4.0.5 for the preg_replace_callback function
  10047. //
  10048. if (!IsPHPAtLeast("4.0.5"))
  10049. SendAlert(GetMessage(MSG_PHP_PLAIN_TEMPLATES,
  10050. array("PHPVERS"=>implode(".",$aPHPVERSION))));
  10051. else
  10052. {
  10053. $s_template = GetMailOption("PlainTemplate");
  10054. if (ProcessTemplate($s_template,$a_lines,$a_raw_fields,
  10055. GetMailOption('TemplateMissing'),
  10056. 'SubstituteValuePlain'))
  10057. {
  10058. $b_used_template = true;
  10059. $s_unfiltered_results = implode(BODY_LF,$a_lines);
  10060. if ($b_got_filter)
  10061. {
  10062. //
  10063. // with a limited filter, the template goes unfiltered
  10064. // and the named fields get filtered
  10065. //
  10066. if ($b_limited_filter)
  10067. list($s_discard,$s_filtered_results) =
  10068. GetFilteredOutput($a_fld_order,$a_clean_fields,
  10069. $s_filter,$a_filter_list);
  10070. else
  10071. {
  10072. $s_filtered_results = Filter($s_filter,$s_unfiltered_results);
  10073. $s_unfiltered_results = "";
  10074. }
  10075. }
  10076. }
  10077. }
  10078. }
  10079. if (!$b_used_template)
  10080. {
  10081. $res_hdr = "";
  10082. if (IsMailOptionSet("DupHeader"))
  10083. {
  10084. //
  10085. // write some standard mail headers
  10086. //
  10087. $res_hdr = "To: $s_to".BODY_LF;
  10088. if (!empty($s_cc))
  10089. $res_hdr .= "Cc: $s_cc".BODY_LF;
  10090. if (!empty($SPECIAL_VALUES["email"]))
  10091. $res_hdr .= "From: ".MakeFromLine($SPECIAL_VALUES["email"],
  10092. $SPECIAL_VALUES["realname"]).BODY_LF;
  10093. $res_hdr .= BODY_LF;
  10094. if (IsMailOptionSet("StartLine"))
  10095. $res_hdr .= "--START--".BODY_LF; // signals the beginning of the text to filter
  10096. }
  10097. //
  10098. // put the realname and the email address at the top of the results
  10099. // (if not excluded)
  10100. //
  10101. if (!IsMailExcluded("realname"))
  10102. {
  10103. array_unshift($a_fld_order,"realname");
  10104. $a_clean_fields["realname"] = $SPECIAL_VALUES["realname"];
  10105. }
  10106. if (!IsMailExcluded("email"))
  10107. {
  10108. array_unshift($a_fld_order,"email");
  10109. $a_clean_fields["email"] = $SPECIAL_VALUES["email"];
  10110. }
  10111. if ($b_got_filter)
  10112. {
  10113. if ($b_limited_filter)
  10114. list($s_unfiltered_results,$s_filtered_results) =
  10115. GetFilteredOutput($a_fld_order,$a_clean_fields,
  10116. $s_filter,$a_filter_list);
  10117. else
  10118. {
  10119. //
  10120. // make text output and filter it (filter all fields)
  10121. //
  10122. $s_filtered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
  10123. $s_filtered_results = Filter($s_filter,$s_filtered_results);
  10124. }
  10125. }
  10126. else
  10127. {
  10128. //SendAlert("There are ".count($a_fld_order)." fields in the order array");
  10129. //SendAlert("Here is the clean fields array:\r\n".var_export($a_clean_fields,true));
  10130. $s_unfiltered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
  10131. }
  10132. $s_unfiltered_results = $res_hdr.$s_unfiltered_results;
  10133. }
  10134. $s_results = $s_unfiltered_results;
  10135. if ($b_got_filter && !empty($s_filtered_results))
  10136. {
  10137. if (!empty($s_results))
  10138. $s_results .= BODY_LF;
  10139. $s_results .= $s_filtered_results;
  10140. }
  10141. //
  10142. // append the environment variables report
  10143. //
  10144. if (isset($SPECIAL_VALUES["env_report"]) && !empty($SPECIAL_VALUES["env_report"]))
  10145. {
  10146. $s_results .= BODY_LF."==================================".BODY_LF;
  10147. $s_results .= BODY_LF.GetEnvVars(TrimArray(explode(",",$SPECIAL_VALUES["env_report"])),BODY_LF);
  10148. }
  10149. return (array($s_results,$s_unfiltered_results,$s_filtered_results));
  10150. }
  10151. //
  10152. // Return the list of fields to be filtered, FALSE if no list provided.
  10153. //
  10154. function GetFilterList($b_file_fields)
  10155. {
  10156. global $SPECIAL_VALUES;
  10157. //
  10158. // no filter means no list of fields
  10159. //
  10160. if (!empty($SPECIAL_VALUES["filter"]))
  10161. {
  10162. if ($b_file_fields)
  10163. {
  10164. if (isset($SPECIAL_VALUES["filter_files"]) && !empty($SPECIAL_VALUES["filter_files"]))
  10165. return (TrimArray(explode(",",$SPECIAL_VALUES["filter_files"])));
  10166. }
  10167. else
  10168. {
  10169. if (isset($SPECIAL_VALUES["filter_fields"]) && !empty($SPECIAL_VALUES["filter_fields"]))
  10170. return (TrimArray(explode(",",$SPECIAL_VALUES["filter_fields"])));
  10171. }
  10172. }
  10173. return (false);
  10174. }
  10175. /*
  10176. * Function: GetFilterSpec
  10177. * Parameters: $s_filter returns the filter name
  10178. * $m_filter_list returns the list of fields to filter (an array)
  10179. * or is set to false if there is no filter list
  10180. * $b_file_fields if true, return file fields, otherwise return non-file fields
  10181. * Returns: bool true if filtering a list of fields of the specified type
  10182. * Description:
  10183. * Checks whether the form has specified to filter a list of
  10184. * fields of the specified type (file fields or non-file fields).
  10185. */
  10186. function GetFilterSpec(&$s_filter,&$m_filter_list,$b_file_fields = false)
  10187. {
  10188. global $SPECIAL_VALUES;
  10189. if (isset($SPECIAL_VALUES["filter"]) && !empty($SPECIAL_VALUES["filter"]))
  10190. {
  10191. $s_filter = $SPECIAL_VALUES["filter"];
  10192. $m_filter_list = GetFilterList($b_file_fields);
  10193. return (true);
  10194. }
  10195. return (false);
  10196. }
  10197. //
  10198. // send the given results to the given email addresses
  10199. //
  10200. function SendResults($a_fld_order,$a_clean_fields,$s_to,$s_cc,$s_bcc,$a_raw_fields)
  10201. {
  10202. global $SPECIAL_VALUES,$aFileVars,$FILE_REPOSITORY,$FIXED_SENDER;
  10203. //
  10204. // check for a filter and how to use it
  10205. //
  10206. $b_filter_attach = false;
  10207. $a_attach_spec = array();
  10208. $s_filter = "";
  10209. $a_filter_list = array();
  10210. if ($b_got_filter = GetFilterSpec($s_filter,$a_filter_list))
  10211. {
  10212. if ($a_filter_list === false)
  10213. {
  10214. //
  10215. // not a limited filter, so filter all fields
  10216. //
  10217. $b_limited_filter = false;
  10218. $a_filter_list = array();
  10219. }
  10220. else
  10221. $b_limited_filter = true;
  10222. FMDebug("SendResults: got filter '$s_filter', limited=$b_limited_filter");
  10223. $s_filter_attach_name = GetFilterOption("Attach");
  10224. if (isset($s_filter_attach_name))
  10225. if (!is_string($s_filter_attach_name) || empty($s_filter_attach_name))
  10226. SendAlert(GetMessage(MSG_ATTACH_NAME));
  10227. else
  10228. {
  10229. $b_filter_attach = true;
  10230. $a_attach_spec = array("Name"=>$s_filter_attach_name);
  10231. if (($s_mime = GetFilterAttrib($s_filter,"MIME")) !== false)
  10232. $a_attach_spec["MIME"] = $s_mime;
  10233. //
  10234. // Regarding the character set...
  10235. // A filter will not generally change the character set
  10236. // of the message, however, if it does, then we
  10237. // provide that information to the MIME encoder.
  10238. // Remember: this character set specification refers
  10239. // to the data *after* the effect of the filter
  10240. // has been reversed (e.g. an encrypted message
  10241. // in UTF-8 is in UTF-8 when it is decrypted).
  10242. //
  10243. if (($s_cset = GetFilterAttrib($s_filter,"CharSet")) !== false)
  10244. $a_attach_spec["CharSet"] = $s_cset;
  10245. }
  10246. }
  10247. //
  10248. // check the need for MIME formatted mail
  10249. //
  10250. $b_mime_mail = (IsMailOptionSet("HTMLTemplate") || count($aFileVars) > 0 ||
  10251. $b_filter_attach);
  10252. //
  10253. // create the email header lines - CC, BCC, From, and Reply-To
  10254. //
  10255. $a_headers = array();
  10256. if (!empty($s_cc))
  10257. $a_headers['Cc'] = SafeHeader($s_cc);
  10258. if (!empty($SPECIAL_VALUES["replyto"]))
  10259. {
  10260. //
  10261. // expand replyto list
  10262. //
  10263. CheckEmailAddress($SPECIAL_VALUES["replyto"],$s_list,$s_invalid,false);
  10264. if (!empty($s_list))
  10265. $a_headers['Reply-To'] = SafeHeader($s_list);
  10266. }
  10267. //
  10268. // note that BCC is documented to not work prior to PHP 4.3
  10269. //
  10270. if (!empty($s_bcc))
  10271. {
  10272. global $aPHPVERSION;
  10273. if ($aPHPVERSION[0] < 4 || ($aPHPVERSION[0] == 4 && $aPHPVERSION[1] < 3))
  10274. SendAlert(GetMessage(MSG_PHP_BCC,
  10275. array("PHPVERS"=>implode(".",$aPHPVERSION))));
  10276. $a_headers['Bcc'] = SafeHeader($s_bcc);
  10277. }
  10278. //
  10279. // create the From address
  10280. //
  10281. // Some servers won't let you set the email address to the
  10282. // submitter of the form. Therefore, use FromAddr if it's been
  10283. // specified to set the sender and the "From" address.
  10284. //
  10285. $s_sender = GetMailOption("FromAddr");
  10286. if (!isset($s_sender))
  10287. {
  10288. $s_sender = "";
  10289. if (!empty($SPECIAL_VALUES["email"]))
  10290. $a_headers['From'] = MakeFromLine($SPECIAL_VALUES["email"],
  10291. $SPECIAL_VALUES["realname"]);
  10292. }
  10293. elseif ($s_sender !== "")
  10294. $s_sender = $a_headers['From'] = SafeHeader(UnMangle($s_sender));
  10295. /*
  10296. * Override sender if $FIXED_SENDER is set.
  10297. */
  10298. if ($FIXED_SENDER !== "")
  10299. $s_sender = $FIXED_SENDER;
  10300. if ($s_sender === "")
  10301. if (SET_SENDER_FROM_EMAIL)
  10302. $s_sender = $SPECIAL_VALUES["email"];
  10303. //
  10304. // special case: if there is only one non-special string value, then
  10305. // format it as an email (unless an option says not to)
  10306. //
  10307. $a_keys = array_keys($a_raw_fields);
  10308. if (count($a_keys) == 1 && is_string($a_raw_fields[$a_keys[0]]) &&
  10309. !IsMailOptionSet("AlwaysList") && !IsMailOptionSet("DupHeader"))
  10310. {
  10311. if (IsMailExcluded($a_keys[0]))
  10312. SendAlert("Exclusion of single field '".$a_keys[0]."' ignored");
  10313. $s_value = $a_raw_fields[$a_keys[0]];
  10314. //
  10315. // replace carriage return/linefeeds with <br>
  10316. //
  10317. $s_value = str_replace("\r\n",'<br />',$s_value);
  10318. //
  10319. // replace lone linefeeds with <br>
  10320. //
  10321. $s_value = str_replace("\n",'<br />',$s_value);
  10322. //
  10323. // remove lone carriage returns
  10324. //
  10325. $s_value = str_replace("\r","",$s_value);
  10326. //
  10327. // replace all control chars with <br />
  10328. //
  10329. $s_value = preg_replace('/[[:cntrl:]]+/','<br />',$s_value);
  10330. //
  10331. // strip HTML (note that all the <br> above will now be
  10332. // replaced with BODY_LF)
  10333. //
  10334. $s_value = StripHTML($s_value,BODY_LF);
  10335. if ($b_mime_mail)
  10336. {
  10337. if ($b_got_filter)
  10338. {
  10339. //
  10340. // filter the whole value (ignore filter_fields for this
  10341. // special case) if a filter has been specified
  10342. //
  10343. $s_results = Filter($s_filter,$s_value);
  10344. if ($b_filter_attach)
  10345. {
  10346. $a_attach_spec["Data"] = $s_results;
  10347. //
  10348. // KeepInLine keeps the filtered version inline as well
  10349. // as an attachment
  10350. //
  10351. if (!IsFilterOptionSet("KeepInLine"))
  10352. $s_results = "";
  10353. $s_filter = ""; // no more filtering
  10354. }
  10355. }
  10356. else
  10357. $s_results = $s_value;
  10358. //
  10359. // send this single value off to get formatted in a MIME
  10360. // email
  10361. //
  10362. if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
  10363. GetMailOption('HTMLTemplate'),
  10364. GetMailOption('TemplateMissing'),
  10365. IsMailOptionSet("NoPlain"),
  10366. $s_filter,$aFileVars,$a_attach_spec))
  10367. return (false);
  10368. }
  10369. elseif ($b_got_filter)
  10370. //
  10371. // filter the whole value (ignore filter_fields for this special case)
  10372. // if a filter has been specified
  10373. //
  10374. $s_results = Filter($s_filter,$s_value);
  10375. else
  10376. {
  10377. $s_results = $s_value;
  10378. if (IsMailOptionSet("CharSet"))
  10379. //
  10380. // sending plain text email, and the CharSet has been
  10381. // specified; include a header
  10382. //
  10383. $a_headers['Content-Type'] = "text/plain; charset=".SafeHeader(GetMailOption("CharSet"));
  10384. }
  10385. }
  10386. else
  10387. {
  10388. if ($b_mime_mail)
  10389. {
  10390. //
  10391. // get the plain text version of the email then send it
  10392. // to get MIME formatted
  10393. //
  10394. list($s_results,$s_unfiltered_results,$s_filtered_results) =
  10395. MakePlainEmail($a_fld_order,$a_clean_fields,
  10396. $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
  10397. $a_filter_list);
  10398. if ($b_filter_attach)
  10399. {
  10400. //
  10401. // attached the filtered results
  10402. //
  10403. $a_attach_spec["Data"] = $s_filtered_results;
  10404. //
  10405. // KeepInLine keeps the filtered version inline as well
  10406. // as an attachment
  10407. //
  10408. if (!IsFilterOptionSet("KeepInLine"))
  10409. //
  10410. // put the unfiltered results in the body of the message
  10411. //
  10412. $s_results = $s_unfiltered_results;
  10413. $s_filter = ""; // no more filtering
  10414. }
  10415. if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
  10416. GetMailOption('HTMLTemplate'),
  10417. GetMailOption('TemplateMissing'),
  10418. IsMailOptionSet("NoPlain"),
  10419. $s_filter,$aFileVars,$a_attach_spec))
  10420. return (false);
  10421. }
  10422. else
  10423. {
  10424. list($s_results,$s_unfiltered_results,$s_filtered_results) =
  10425. MakePlainEmail($a_fld_order,$a_clean_fields,
  10426. $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
  10427. $a_filter_list);
  10428. if (!$b_got_filter && IsMailOptionSet("CharSet"))
  10429. //
  10430. // sending plain text email, and the CharSet has been
  10431. // specified; include a header
  10432. //
  10433. $a_headers['Content-Type'] = "text/plain; charset=".SafeHeader(GetMailOption("CharSet"));
  10434. }
  10435. }
  10436. //
  10437. // now save uploaded files to the repository
  10438. //
  10439. if (FILEUPLOADS && $FILE_REPOSITORY !== "")
  10440. if (!SaveAllFilesToRepository())
  10441. return (false);
  10442. //
  10443. // send the mail - assumes the email addresses have already been checked
  10444. //
  10445. return (SendCheckedMail($s_to,$SPECIAL_VALUES["subject"],$s_results,
  10446. $s_sender,$a_headers));
  10447. }
  10448. //
  10449. // append an entry to a log file
  10450. //
  10451. function WriteLog($log_file)
  10452. {
  10453. global $SPECIAL_VALUES,$php_errormsg;
  10454. @ $log_fp = fopen($log_file,"a");
  10455. if ($log_fp === false)
  10456. {
  10457. SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$log_file,
  10458. "TYPE"=>"log",
  10459. "ERROR"=>CheckString($php_errormsg))));
  10460. return;
  10461. }
  10462. $date = gmdate("H:i:s d-M-y T");
  10463. $entry = $date.":".$SPECIAL_VALUES["email"].",".
  10464. $SPECIAL_VALUES["realname"].",".$SPECIAL_VALUES["subject"]."\n";
  10465. fwrite($log_fp,$entry);
  10466. fclose($log_fp);
  10467. }
  10468. //
  10469. // write the data to a comma-separated-values file
  10470. //
  10471. function WriteCSVFile($s_csv_file,$a_vars)
  10472. {
  10473. global $SPECIAL_VALUES,$CSVSEP,$CSVINTSEP,$CSVQUOTE,$CSVOPEN,$CSVLINE;
  10474. //
  10475. // create an array of column values in the order specified
  10476. // in $SPECIAL_VALUES["csvcolumns"]
  10477. //
  10478. $a_column_list = $SPECIAL_VALUES["csvcolumns"];
  10479. if (!isset($a_column_list) || empty($a_column_list) || !is_string($a_column_list))
  10480. {
  10481. SendAlert(GetMessage(MSG_CSVCOLUMNS,array("VALUE"=>$a_column_list)));
  10482. return;
  10483. }
  10484. if (!isset($s_csv_file) || empty($s_csv_file) || !is_string($s_csv_file))
  10485. {
  10486. SendAlert(GetMessage(MSG_CSVFILE,array("VALUE"=>$s_csv_file)));
  10487. return;
  10488. }
  10489. @ $fp = fopen($s_csv_file,"a".$CSVOPEN);
  10490. if ($fp === false)
  10491. {
  10492. SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_csv_file,
  10493. "TYPE"=>"CSV",
  10494. "ERROR"=>CheckString($php_errormsg))));
  10495. return;
  10496. }
  10497. //
  10498. // convert the column list to an array, trim the names too
  10499. //
  10500. $a_column_list = TrimArray(explode(",",$a_column_list));
  10501. $n_columns = count($a_column_list);
  10502. //
  10503. // if the file is currently empty, put the column names in the first line
  10504. //
  10505. $b_heading = false;
  10506. if (filesize($s_csv_file) == 0)
  10507. $b_heading = true;
  10508. $csv_format = new CSVFormat();
  10509. //
  10510. // now configure the CSVFormat object
  10511. // according to FormMail's configuration settings
  10512. //
  10513. $csv_format->SetQuote($CSVQUOTE);
  10514. $csv_format->SetEscPolicy("conv");
  10515. $csv_format->SetSep($CSVSEP);
  10516. $csv_format->SetIntSep($CSVINTSEP);
  10517. if (LIMITED_IMPORT)
  10518. $csv_format->SetCleanFunc(create_function('$m_value',
  10519. 'return CleanValue($m_value);'));
  10520. $s_csv = $csv_format->MakeCSVRecord($a_column_list,$a_vars);
  10521. if ($b_heading)
  10522. fwrite($fp,$csv_format->MakeHeading($a_column_list).$CSVLINE);
  10523. fwrite($fp,$s_csv.$CSVLINE);
  10524. fclose($fp);
  10525. // CreatePage($debug);
  10526. // exit;
  10527. }
  10528. function CheckConfig()
  10529. {
  10530. global $TARGET_EMAIL,$CONFIG_CHECK;
  10531. $a_mesgs = array();
  10532. if (in_array("TARGET_EMAIL",$CONFIG_CHECK))
  10533. {
  10534. //
  10535. // $TARGET_EMAIL values should begin with ^ and end with $
  10536. //
  10537. for ($ii = 0 ; $ii < count($TARGET_EMAIL) ; $ii++)
  10538. {
  10539. $s_pattern = $TARGET_EMAIL[$ii];
  10540. if (substr($s_pattern,0,1) != '^')
  10541. $a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_START,
  10542. array("PAT"=>$s_pattern));
  10543. if (substr($s_pattern,-1) != '$')
  10544. $a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_END,
  10545. array("PAT"=>$s_pattern));
  10546. }
  10547. }
  10548. if (count($a_mesgs) > 0)
  10549. SendAlert(GetMessage(MSG_CONFIG_WARN,
  10550. array("MESGS"=>implode("\n",$a_mesgs))),false,true);
  10551. }
  10552. //
  10553. // append an entry to the Auto Responder log file
  10554. //
  10555. function WriteARLog($s_to,$s_subj,$s_info)
  10556. {
  10557. global $LOGDIR,$AUTORESPONDLOG,$aServerVars,$php_errormsg;
  10558. if (!isset($LOGDIR) || !isset($AUTORESPONDLOG) ||
  10559. empty($LOGDIR) || empty($AUTORESPONDLOG))
  10560. return;
  10561. $log_file = $LOGDIR."/".$AUTORESPONDLOG;
  10562. @ $log_fp = fopen($log_file,"a");
  10563. if ($log_fp === false)
  10564. {
  10565. SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$log_file,
  10566. "TYPE"=>"log",
  10567. "ERROR"=>CheckString($php_errormsg))));
  10568. return;
  10569. }
  10570. $a_entry = array();
  10571. $a_entry[] = gmdate("H:i:s d-M-y T"); // date/time in GMT
  10572. $a_entry[] = $aServerVars['REMOTE_ADDR']; // remote IP address
  10573. $a_entry[] = $s_to; // target email address
  10574. $a_entry[] = $s_subj; // subject line
  10575. $a_entry[] = $s_info; // information
  10576. $s_log_entry = implode(",",$a_entry)."\n";
  10577. fwrite($log_fp,$s_log_entry);
  10578. fclose($log_fp);
  10579. }
  10580. /*
  10581. * The main logic starts here....
  10582. */
  10583. //
  10584. // First, a special case; if formmail.php is called like this:
  10585. // http://.../formmail.php?testalert=1
  10586. // it sends a test message to the default alert address with some
  10587. // information about your PHP version and the DOCUMENT_ROOT.
  10588. //
  10589. if (isset($aGetVars["testalert"]) && $aGetVars["testalert"] == 1)
  10590. {
  10591. function ShowServerVar($s_name)
  10592. {
  10593. global $aServerVars;
  10594. return (isset($aServerVars[$s_name]) ? $aServerVars[$s_name] : "-not set-");
  10595. }
  10596. $sAlert = GetMessage(MSG_ALERT,
  10597. array("LANG"=>$sLangID,
  10598. "PHPVERS"=>implode(".",$aPHPVERSION),
  10599. "FM_VERS"=>$FM_VERS,
  10600. "SERVER"=>(IsServerWindows() ? "Windows" : "non-Windows"),
  10601. "DOCUMENT_ROOT"=>ShowServerVar('DOCUMENT_ROOT'),
  10602. "SCRIPT_FILENAME"=>ShowServerVar('SCRIPT_FILENAME'),
  10603. "PATH_TRANSLATED"=>ShowServerVar('PATH_TRANSLATED'),
  10604. "REAL_DOCUMENT_ROOT"=>CheckString($REAL_DOCUMENT_ROOT),
  10605. ));
  10606. if (DEF_ALERT == "")
  10607. echo "<p>".GetMessage(MSG_NO_DEF_ALERT)."</p>";
  10608. elseif (SendAlert($sAlert,false,true))
  10609. echo "<p>".GetMessage(MSG_TEST_SENT)."</p>";
  10610. else
  10611. echo "<p>".GetMessage(MSG_TEST_FAILED)."</p>";
  10612. exit;
  10613. }
  10614. if (isset($aGetVars["testlang"]) && $aGetVars["testlang"] == 1)
  10615. {
  10616. if (!IsPHPAtLeast("4.1.0"))
  10617. {
  10618. ?>
  10619. <p>testlang feature only works with PHP version 4.1.0 or later</p>
  10620. <?php
  10621. }
  10622. else
  10623. {
  10624. function ShowMessages()
  10625. {
  10626. global $aMessages,$sLangID,$bShowMesgNumbers,$aGetVars,$sHTMLCharSet;
  10627. //
  10628. // force message numbers on unless "mnums=no"
  10629. //
  10630. if (isset($aGetVars["mnums"]) && $aGetVars["mnums"] == "no")
  10631. $bShowMesgNumbers = false;
  10632. else
  10633. $bShowMesgNumbers = true;
  10634. LoadBuiltinLanguage();
  10635. $s_def_lang = $sLangID;
  10636. $a_def_mesgs = $aMessages;
  10637. LoadLanguageFile();
  10638. $s_active_lang = $sLangID;
  10639. $a_active_mesgs = $aMessages;
  10640. $a_list = get_defined_constants();
  10641. echo "<html>\n";
  10642. echo "<head>\n";
  10643. if (isset($sHTMLCharSet) && $sHTMLCharSet !== "")
  10644. echo "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=$sHTMLCharSet\">\n";
  10645. echo "</head>\n";
  10646. echo "<body>\n";
  10647. echo "<table border=\"1\" cellpadding=\"10\" width=\"95%\">\n";
  10648. echo "<tr>\n";
  10649. echo "<th>\n";
  10650. echo "Message Number";
  10651. echo "</th>\n";
  10652. echo "<th>\n";
  10653. echo "$s_def_lang";
  10654. echo "</th>\n";
  10655. echo "<th>\n";
  10656. echo "$s_active_lang";
  10657. echo "</th>\n";
  10658. echo "</tr>\n";
  10659. foreach ($a_list as $s_name=>$i_value)
  10660. {
  10661. if (substr($s_name,0,4) == "MSG_")
  10662. {
  10663. //
  10664. // some PHP constants begin with MSG_, so we try to skip them too
  10665. //
  10666. switch ($s_name)
  10667. {
  10668. case "MSG_IPC_NOWAIT":
  10669. case "MSG_EAGAIN":
  10670. case "MSG_ENOMSG":
  10671. case "MSG_NOERROR":
  10672. case "MSG_EXCEPT":
  10673. case "MSG_OOB":
  10674. case "MSG_PEEK":
  10675. case "MSG_DONTROUTE":
  10676. case "MSG_EOR":
  10677. continue 2;
  10678. }
  10679. if ($i_value >= 256)
  10680. continue;
  10681. echo "<tr>\n";
  10682. echo "<td valign=\"top\">\n";
  10683. echo "$s_name ($i_value)";
  10684. echo "</td>\n";
  10685. echo "<td valign=\"top\">\n";
  10686. $aMessages = $a_def_mesgs;
  10687. $s_def_msg = GetMessage((int) $i_value,array(),true,true);
  10688. echo nl2br(htmlentities($s_def_msg)); // English - don't need FixedHTMLEntities
  10689. echo "</td>\n";
  10690. echo "<td valign=\"top\">\n";
  10691. $aMessages = $a_active_mesgs;
  10692. $s_act_msg = GetMessage((int) $i_value,array(),true,true);
  10693. if ($s_def_msg == $s_act_msg)
  10694. echo "<i>identical</i>\n";
  10695. else
  10696. echo nl2br(FixedHTMLEntities($s_act_msg));
  10697. echo "</td>\n";
  10698. echo "</tr>\n";
  10699. }
  10700. }
  10701. echo "</table>\n";
  10702. echo "</body>\n";
  10703. echo "</html>\n";
  10704. }
  10705. ShowMessages();
  10706. }
  10707. exit;
  10708. }
  10709. //
  10710. // For saved files, add in the "new_name" values to the given
  10711. // array.
  10712. //
  10713. function GetSavedFileNames($a_values)
  10714. {
  10715. if (IsSetSession("FormSavedFiles"))
  10716. {
  10717. $a_saved_files = GetSession("FormSavedFiles");
  10718. foreach ($a_saved_files as $s_fld=>$a_upload)
  10719. {
  10720. if (isset($a_upload["name"]))
  10721. $a_values[$s_fld] = $a_upload["name"];
  10722. if (isset($a_upload["new_name"]))
  10723. $a_values["name_of_$s_fld"] = $a_upload["new_name"];
  10724. }
  10725. }
  10726. return ($a_values);
  10727. }
  10728. //
  10729. // Scan the Multi form sequence values and build up the values that
  10730. // were submitted to the given form index.
  10731. //
  10732. function GetMultiValues($a_form_list,$i_form_index,$a_order = array(),
  10733. $a_clean = array(),
  10734. $a_raw_data = array(),
  10735. $a_all_data = array(),
  10736. $a_file_data = array())
  10737. {
  10738. $a_ret_clean = $a_ret_raw = $a_ret_all = $a_ret_files = array();
  10739. for ($ii = 0 ; $ii < $i_form_index ; $ii++)
  10740. {
  10741. //
  10742. // only add a field to the order if it's not already there
  10743. //
  10744. $a_form_order = $a_form_list[$ii]["ORDER"];
  10745. $n_order = count($a_form_order);
  10746. for ($jj = 0 ; $jj < $n_order ; $jj++)
  10747. {
  10748. if (array_search($a_form_order[$jj],$a_order) === false)
  10749. $a_order[] = $a_form_order[$jj];
  10750. }
  10751. $a_ret_clean = array_merge($a_ret_clean,$a_form_list[$ii]["CLEAN"]);
  10752. $a_ret_raw = array_merge($a_ret_raw,$a_form_list[$ii]["RAWDATA"]);
  10753. $a_ret_all = array_merge($a_ret_all,$a_form_list[$ii]["ALLDATA"]);
  10754. $a_ret_files = array_merge($a_ret_files,$a_form_list[$ii]["FILES"]);
  10755. }
  10756. //
  10757. // later values must take precedence to earlier values,
  10758. // so merge in the passed-in data last
  10759. //
  10760. $a_ret_clean = array_merge($a_ret_clean,$a_clean);
  10761. $a_ret_raw = array_merge($a_ret_raw,$a_raw_data);
  10762. $a_ret_all = array_merge($a_ret_all,$a_all_data);
  10763. $a_ret_files = array_merge($a_ret_files,$a_file_data);
  10764. return (array($a_order,$a_ret_clean,$a_ret_raw,$a_ret_all,$a_ret_files));
  10765. }
  10766. $bMultiForm = false;
  10767. //
  10768. // Multi-page form sequencing is complicated....
  10769. // Requirements:
  10770. // 1. The first page in a multi-page form sequence must provide:
  10771. // - multi_start field set to 1
  10772. // - this_form field (it's own URL)
  10773. // - next_form field (multi-page form template name)
  10774. // 2. Subsequent pages must provide either:
  10775. // next_form (the next template name in the sequence)
  10776. // OR
  10777. // good_url or good_template or neither; this terminates
  10778. // the multi-page processing and provides the final URL.
  10779. // Logic:
  10780. // 1. We create session variables to contain information about
  10781. // the sequence.
  10782. // 2. On the first submission from the starting form, we record
  10783. // its "this_form" URL and the data submitted.
  10784. // We also create a URL (to FormMail) that will allow return
  10785. // to the *next* form in the sequence.
  10786. // 3. On submission from other forms in the sequence, we record
  10787. // the data that was submitted so we can return to that
  10788. // form with the user's data re-filled into the form.
  10789. // We also create a URL (to FormMail) that will allow return
  10790. // to the *next* form in the sequence.
  10791. // 4. A return URL contains "return=index" where index is the
  10792. // form sequence index number. This is a URL to FormMail.
  10793. // FormMail gets the template name or URL (URL only for the
  10794. // starting form) and outputs the requested HTML form. It also
  10795. // truncates the session data for forms after the returned-to
  10796. // one.
  10797. //
  10798. //
  10799. // Return to a previous form in a sequence.
  10800. //
  10801. function MultiFormReturn($i_return_to)
  10802. {
  10803. global $iFormIndex;
  10804. global $SessionAccessor;
  10805. if (!IsSetSession("FormList") ||
  10806. !IsSetSession("FormIndex") ||
  10807. $i_return_to < 0 ||
  10808. $i_return_to > GetSession("FormIndex"))
  10809. Error("cannot_return",GetMessage(MSG_CANNOT_RETURN,
  10810. array("TO"=>$i_return_to,
  10811. "TOPINDEX"=>(
  10812. IsSetSession("FormIndex") ?
  10813. GetSession("FormIndex") :
  10814. "<undefined>"))),
  10815. false,false);
  10816. $a_list = GetSession("FormList");
  10817. assert($i_return_to < count($a_list));
  10818. $a_form_def = $a_list[$i_return_to];
  10819. SetSession("FormList",$a_list = array_slice($a_list,0,$i_return_to+1));
  10820. SetSession("FormIndex",$iFormIndex = $i_return_to);
  10821. if (isset($a_form_def["FORM"]))
  10822. {
  10823. //
  10824. // get the values that were originally submitted to this form
  10825. //
  10826. list(,,$a_values,,) = GetMultiValues($a_list,$i_return_to);
  10827. //
  10828. // get the session values
  10829. //
  10830. $SessionAccessor->CopyIn($a_values,true);
  10831. $a_lines = array();
  10832. //
  10833. // process the page as a template
  10834. //
  10835. if (ProcessMultiFormTemplate($a_form_def["FORM"],$a_values,$a_lines))
  10836. {
  10837. $n_lines = count($a_lines);
  10838. $s_buf = "";
  10839. for ($ii = 0 ; $ii < $n_lines ; $ii++)
  10840. {
  10841. $s_buf .= $a_lines[$ii]."\n";
  10842. unset($a_lines[$ii]); // free memory (hopefully)
  10843. }
  10844. unset($a_lines); // free memory (hopefully)
  10845. //
  10846. // put in the values that the user previously submitted
  10847. // to this form
  10848. //
  10849. echo SetPreviousValues($s_buf,$a_form_def["RAWDATA"]);
  10850. }
  10851. else
  10852. Error("multi_form_failed",GetMessage(MSG_MULTIFORM_FAILED,
  10853. array("NAME"=>$s_template)),false,false);
  10854. }
  10855. else
  10856. //
  10857. // we probably should include
  10858. // $SessionAccessor->CopyIn(...,true);
  10859. // at some stage in the future to get the session values....need to think about this
  10860. // and run some case studies.
  10861. //
  10862. ProcessReturnToForm($a_form_def["URL"],$a_form_def["RAWDATA"],array("multi_start"));
  10863. //echo "Returned to $i_return_to";
  10864. }
  10865. //
  10866. // Store any data just submitted and specified as "multi_keep".
  10867. //
  10868. function MultiKeep()
  10869. {
  10870. global $SPECIAL_VALUES,$aRawDataValues;
  10871. if (isset($SPECIAL_VALUES["multi_keep"]) &&
  10872. !empty($SPECIAL_VALUES["multi_keep"]))
  10873. {
  10874. $a_list = TrimArray(explode(",",$SPECIAL_VALUES["multi_keep"]));
  10875. if (IsSetSession("FormKeep"))
  10876. $a_keep = GetSession("FormKeep");
  10877. else
  10878. $a_keep = array();
  10879. //
  10880. // For each data field specified in "multi_keep" store its
  10881. // value in the FormKeep session variable.
  10882. // If a field is specified and does not exist in the
  10883. // recent submission, its value is discarded.
  10884. //
  10885. foreach ($a_list as $s_fld_name)
  10886. if (!empty($s_fld_name))
  10887. if (isset($aRawDataValues[$s_fld_name]))
  10888. $a_keep[$s_fld_name] = $aRawDataValues[$s_fld_name];
  10889. else
  10890. unset($a_keep[$s_fld_name]);
  10891. SetSession("FormKeep",$a_keep);
  10892. }
  10893. }
  10894. //
  10895. // Perform Logic for Multi-Page form sequences
  10896. //
  10897. function MultiFormLogic()
  10898. {
  10899. global $bMultiForm,$SPECIAL_VALUES,$aServerVars,$aFileVars;
  10900. global $sFormMailScript,$bGotGoBack,$bGotNextForm,$iFormIndex;
  10901. global $aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues;
  10902. if ($SPECIAL_VALUES["multi_start"] == 1)
  10903. {
  10904. if (empty($SPECIAL_VALUES["this_form"]))
  10905. ErrorWithIgnore("need_this_form",GetMessage(MSG_NEED_THIS_FORM),false,false);
  10906. $bMultiForm = true;
  10907. //
  10908. // Start of multi-page form sequence
  10909. //
  10910. $a_list = array();
  10911. $a_list[0] = array("URL"=>$SPECIAL_VALUES["this_form"],
  10912. "ORDER"=>$aFieldOrder,
  10913. "CLEAN"=>$aCleanedValues,
  10914. "RAWDATA"=>$aRawDataValues,
  10915. "ALLDATA"=>$aAllRawValues,
  10916. "FILES"=>$aFileVars);
  10917. $iFormIndex = 0; // zero is the first form, which was just submitted
  10918. SetSession("FormList",$a_list);
  10919. SetSession("FormIndex",$iFormIndex);
  10920. //
  10921. // this is a fresh session, so remove any remembered values
  10922. //
  10923. UnsetSession("FormSavedFiles");
  10924. UnsetSession("FormKeep");
  10925. }
  10926. elseif (IsSetSession("FormList"))
  10927. $bMultiForm = true;
  10928. if ($bMultiForm)
  10929. {
  10930. if (isset($aServerVars["PHP_SELF"]) &&
  10931. !empty($aServerVars["PHP_SELF"]) &&
  10932. isset($aServerVars["SERVER_NAME"]) &&
  10933. !empty($aServerVars["SERVER_NAME"]))
  10934. {
  10935. if (isset($aServerVars["SERVER_PORT"]) &&
  10936. $aServerVars["SERVER_PORT"] != 80)
  10937. {
  10938. if ($aServerVars["SERVER_PORT"] == 443) // SSL port
  10939. //
  10940. // just use https prefix
  10941. //
  10942. $sFormMailScript = "https://".$aServerVars["SERVER_NAME"].
  10943. $aServerVars["PHP_SELF"];
  10944. else
  10945. //
  10946. // use http with port number
  10947. //
  10948. $sFormMailScript = "http://".$aServerVars["SERVER_NAME"].
  10949. ":".$aServerVars["SERVER_PORT"].
  10950. $aServerVars["PHP_SELF"];
  10951. }
  10952. else
  10953. $sFormMailScript = "http://".$aServerVars["SERVER_NAME"].
  10954. $aServerVars["PHP_SELF"];
  10955. $iFormIndex = GetSession("FormIndex");
  10956. }
  10957. else
  10958. Error("no_php_self",GetMessage(MSG_NO_PHP_SELF),false,false);
  10959. }
  10960. //
  10961. // If we're going forward in a multi-page form sequence,
  10962. // compute a URL to return to the form we're about to display.
  10963. //
  10964. if ($bMultiForm && !$bGotGoBack)
  10965. {
  10966. //
  10967. // record the data that was just submitted by the previous form
  10968. //
  10969. $iFormIndex = GetSession("FormIndex");
  10970. $a_list = GetSession("FormList");
  10971. $a_list[$iFormIndex]["ORDER"] = $aFieldOrder;
  10972. $a_list[$iFormIndex]["CLEAN"] = $aCleanedValues;
  10973. $a_list[$iFormIndex]["RAWDATA"] = $aRawDataValues;
  10974. $a_list[$iFormIndex]["ALLDATA"] = $aAllRawValues;
  10975. if (count($aFileVars) > 0 && !FILEUPLOADS)
  10976. SendAlert(GetMessage(MSG_FILE_UPLOAD));
  10977. elseif (count($aFileVars) > 0 && !SaveAllUploadedFiles($aFileVars))
  10978. Error("upload_save_failed",GetMessage(MSG_MULTI_UPLOAD),false,false);
  10979. $a_list[$iFormIndex]["FILES"] = $aFileVars;
  10980. $iFormIndex++;
  10981. $s_url = GetReturnLink($sFormMailScript,$iFormIndex);
  10982. $a_list[$iFormIndex] = array("URL"=>$s_url,
  10983. "FORM"=>$SPECIAL_VALUES["next_form"],
  10984. "ORDER"=>$aFieldOrder,
  10985. "CLEAN"=>$aCleanedValues,
  10986. "RAWDATA"=>$aRawDataValues,
  10987. "ALLDATA"=>$aAllRawValues,
  10988. "FILES"=>$aFileVars);
  10989. SetSession("FormList",$a_list);
  10990. SetSession("FormIndex",$iFormIndex);
  10991. MultiKeep();
  10992. }
  10993. }
  10994. //
  10995. // Check for the MIME Attack
  10996. //
  10997. function DetectMimeAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  10998. {
  10999. //
  11000. // if any of the recipient fields contain "MIME-Version" or
  11001. // "Content-Type" then this is the MIME attack
  11002. // Now also checks the subject field.
  11003. //
  11004. $a_rec_flds = array("recipients","cc","bcc","replyto","subject");
  11005. foreach ($a_rec_flds as $s_fld)
  11006. if (isset($a_fields[$s_fld]))
  11007. {
  11008. //
  11009. // some of the fields can be arrays
  11010. //
  11011. if (is_array($a_fields[$s_fld]))
  11012. $s_data = implode(",",$a_fields[$s_fld]);
  11013. else
  11014. $s_data = $a_fields[$s_fld];
  11015. $s_data = strtolower($s_data);
  11016. if (($i_mime = strpos($s_data,"mime-version")) !== false ||
  11017. ($i_cont = strpos($s_data,"content-type")) !== false)
  11018. {
  11019. $s_attack = "MIME";
  11020. $s_info = GetMessage(MSG_ATTACK_MIME_INFO,
  11021. array("FLD"=>$s_fld,
  11022. "CONTENT"=>($i_mime !== false) ?
  11023. "mime-version" :
  11024. "content-type"),false);
  11025. return (true);
  11026. }
  11027. }
  11028. return (false);
  11029. }
  11030. //
  11031. // Strip common language sequences from the data
  11032. // that might otherwise look like a junk attack.
  11033. // We replace them with a space so that the stripping
  11034. // cannot create more junk accidentally.
  11035. //
  11036. function AttackDetectionStripLang($s_data)
  11037. {
  11038. global $ATTACK_DETECTION_JUNK_LANG_STRIP;
  11039. foreach ($ATTACK_DETECTION_JUNK_LANG_STRIP as $s_seq)
  11040. $s_data = str_replace($s_seq," ",$s_data);
  11041. return ($s_data);
  11042. }
  11043. //
  11044. // Find strings of $n_consec characters from the alphabet of $s_alpha
  11045. // in $s_data. Return the count of instances found.
  11046. //
  11047. function AttackDetectionFindJunk($s_data,$s_alpha,$n_consec,&$a_matches)
  11048. {
  11049. $s_pat = "/[".preg_quote($s_alpha,"/")."]{"."$n_consec,$n_consec"."}/";
  11050. if (($n_count = preg_match_all($s_pat,$s_data,$a_matches)) === false)
  11051. {
  11052. $n_count = 0;
  11053. $a_matches = array();
  11054. }
  11055. else
  11056. $a_matches = $a_matches[0];
  11057. return ($n_count);
  11058. }
  11059. //
  11060. // Check for the Junk Attack
  11061. //
  11062. function DetectJunkAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  11063. {
  11064. global $ATTACK_DETECTION_JUNK_IGNORE_FIELDS;
  11065. //
  11066. // If any field contains junk data, trigger detection.
  11067. //
  11068. $n_count = 0;
  11069. $a_matches = array();
  11070. $a_user_matches = array();
  11071. foreach ($a_fields as $s_fld=>$m_value)
  11072. {
  11073. if (IsSpecialField($s_fld) || IsSpecialMultiField($s_fld))
  11074. {
  11075. //
  11076. // Skip special fields because they don't contain
  11077. // normal user input.
  11078. // But, some special fields do contain normal user
  11079. // input, so we don't skip them.
  11080. //
  11081. $b_skip = true;
  11082. switch ($s_fld)
  11083. {
  11084. case "realname":
  11085. case "subject":
  11086. $b_skip = false;
  11087. break;
  11088. }
  11089. if ($b_skip)
  11090. continue;
  11091. }
  11092. //
  11093. // Ignore fields that are specified to contain
  11094. // technical information.
  11095. //
  11096. if (in_array($s_fld,$ATTACK_DETECTION_JUNK_IGNORE_FIELDS,true))
  11097. continue;
  11098. if (isset($m_value) && !FieldManager::IsEmpty($m_value))
  11099. {
  11100. if (!is_array($m_value))
  11101. $m_value = array($m_value);
  11102. foreach ($m_value as $s_data)
  11103. {
  11104. $s_orig_data = $s_data = strtolower($s_data);
  11105. //
  11106. // Strip out sequences that might be common to
  11107. // the user's language.
  11108. // For example, in English, there are a lot of common
  11109. // words that can easily be protected from our
  11110. // tests. For example, "thousandths" has 5 consecutive consonants
  11111. // but is a reasonable word.
  11112. // Similarly, "queue" has 4 consecutive vowels.
  11113. //
  11114. $s_data = AttackDetectionStripLang($s_data);
  11115. //
  11116. // Look for strings of too many vowels or too many consonants.
  11117. // For safety, we must detect more than one instance, because there
  11118. // are a lot of normal words that may be caught by this test.
  11119. // The number of instances is controlled by configuration.
  11120. //
  11121. $n_match = AttackDetectionFindJunk($s_data,ATTACK_DETECTION_JUNK_CONSONANTS,
  11122. ATTACK_DETECTION_JUNK_CONSEC_CONSONANTS,
  11123. $a_match_cons);
  11124. if ($n_match > 0)
  11125. $a_user_matches[] = $s_orig_data;
  11126. $n_count += $n_match;
  11127. $n_match = AttackDetectionFindJunk($s_data,ATTACK_DETECTION_JUNK_VOWELS,
  11128. ATTACK_DETECTION_JUNK_CONSEC_VOWELS,
  11129. $a_match_vow);
  11130. if ($n_match > 0)
  11131. $a_user_matches[] = $s_orig_data;
  11132. $n_count += $n_match;
  11133. if ($n_count >= ATTACK_DETECTION_JUNK_TRIGGER)
  11134. {
  11135. $a_matches = array_merge($a_matches,$a_match_cons,$a_match_vow);
  11136. $s_user_info = GetMessage(MSG_USER_ATTACK_JUNK,
  11137. array("INPUT"=>implode(", ",$a_user_matches)),false);
  11138. $s_attack = "JUNK";
  11139. $s_info = GetMessage(MSG_ATTACK_JUNK_INFO,
  11140. array("FLD"=>$s_fld,
  11141. "JUNK"=>implode(" ",$a_matches)),false);
  11142. return (true);
  11143. }
  11144. }
  11145. }
  11146. }
  11147. return (false);
  11148. }
  11149. //
  11150. // Check for the duplicate data attack
  11151. //
  11152. function DetectDupAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  11153. {
  11154. //
  11155. // if any of the configured fields contain duplicate data,
  11156. // then this lame attack has been detected
  11157. //
  11158. global $ATTACK_DETECTION_DUPS;
  11159. $a_data_map = array();
  11160. foreach ($ATTACK_DETECTION_DUPS as $s_fld)
  11161. if (isset($a_fields[$s_fld]) &&
  11162. is_scalar($a_fields[$s_fld]) && // can only work with string data
  11163. !empty($a_fields[$s_fld]))
  11164. {
  11165. $s_data = (string) $a_fields[$s_fld];
  11166. if (isset($a_data_map[$s_data]))
  11167. {
  11168. //
  11169. // duplicate found!
  11170. //
  11171. $s_attack = "Duplicate Fields";
  11172. $s_info = GetMessage(MSG_ATTACK_DUP_INFO,
  11173. array("FLD1"=>$a_data_map[$s_data],
  11174. "FLD2"=>$s_fld),false);
  11175. $s_user_info = GetMessage(MSG_USER_ATTACK_DUP,array(),false);
  11176. return (true);
  11177. }
  11178. $a_data_map[$s_data] = $s_fld;
  11179. }
  11180. return (false);
  11181. }
  11182. //
  11183. // Check for the email addresses in specials attack
  11184. //
  11185. function DetectSpecialsAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  11186. {
  11187. global $ATTACK_DETECTION_SPECIALS_ONLY_EMAIL,
  11188. $ATTACK_DETECTION_SPECIALS_ANY_EMAIL;
  11189. //
  11190. // look for email addresses in whole fields
  11191. //
  11192. foreach ($ATTACK_DETECTION_SPECIALS_ONLY_EMAIL as $s_fld)
  11193. {
  11194. if (isset($a_fields[$s_fld]) &&
  11195. is_scalar($a_fields[$s_fld]) && // can only work with string data
  11196. !empty($a_fields[$s_fld]))
  11197. {
  11198. $s_data = $a_fields[$s_fld];
  11199. if (preg_match("/^\b[-a-z0-9._%]+@[-.%_a-z0-9]+\.[a-z]{2,9}\b$/i",
  11200. $s_data) === 1)
  11201. {
  11202. //
  11203. // email address found in wrong field
  11204. //
  11205. $s_attack = "Special Fields Only";
  11206. $s_info = GetMessage(MSG_ATTACK_SPEC_INFO,
  11207. array("FLD"=>$s_fld),false);
  11208. return (true);
  11209. }
  11210. }
  11211. }
  11212. //
  11213. // look for email addresses in any part of fields
  11214. //
  11215. foreach ($ATTACK_DETECTION_SPECIALS_ANY_EMAIL as $s_fld)
  11216. {
  11217. if (isset($a_fields[$s_fld]) &&
  11218. is_scalar($a_fields[$s_fld]) && // can only work with string data
  11219. !empty($a_fields[$s_fld]))
  11220. {
  11221. $s_data = $a_fields[$s_fld];
  11222. if (preg_match("/\b[-a-z0-9._%]+@[-.%_a-z0-9]+\.[a-z]{2,9}\b/i",
  11223. $s_data) > 0)
  11224. {
  11225. //
  11226. // email address found in wrong field
  11227. //
  11228. $s_attack = "Special Fields Any";
  11229. $s_info = GetMessage(MSG_ATTACK_SPEC_INFO,
  11230. array("FLD"=>$s_fld),false);
  11231. return (true);
  11232. }
  11233. }
  11234. }
  11235. return (false);
  11236. }
  11237. //
  11238. // Check for "many URLs in a field" and "many fields with URLs" attacks
  11239. //
  11240. function DetectManyURLsAttack($a_fields,&$s_attack,&$s_info,&$s_user_info)
  11241. {
  11242. global $ATTACK_DETECTION_URL_PATTERNS;
  11243. $a_fld_names = array();
  11244. //
  11245. // actual URL link patterns
  11246. //
  11247. $s_srch = '((\bhttps{0,1}:\/\/|<\s*a\s+href=["'."'".']{0,1})[-a-z0-9.]+\b)';
  11248. //
  11249. // now add configurable patterns
  11250. //
  11251. if (!empty($ATTACK_DETECTION_URL_PATTERNS) &&
  11252. is_array($ATTACK_DETECTION_URL_PATTERNS))
  11253. {
  11254. //
  11255. // escape / characters and build up a string
  11256. // of alternate patterns
  11257. //
  11258. foreach ($ATTACK_DETECTION_URL_PATTERNS as $s_pat)
  11259. {
  11260. if ($s_pat == "")
  11261. continue;
  11262. $s_srch .= "|".str_replace('/','\/',$s_pat);
  11263. }
  11264. }
  11265. foreach ($a_fields as $s_fld=>$s_data)
  11266. {
  11267. if (IsSpecialField($s_fld) || IsSpecialMultiField($s_fld))
  11268. //
  11269. // skip special fields because some are supposed to
  11270. // have URLs in them
  11271. //
  11272. continue;
  11273. if (isset($s_data) &&
  11274. is_scalar($s_data) && // can only work with string data
  11275. !empty($s_data))
  11276. {
  11277. $n_match = preg_match_all("/$s_srch/msi",$s_data,$a_matches);
  11278. if (!is_int($n_match))
  11279. $n_match = 0;
  11280. /*
  11281. * debugging code....
  11282. if ($n_match > 0)
  11283. echo "Pattern is '".htmlentities($s_srch)."' with '".
  11284. htmlentities($s_data)."' field '$s_fld', matched=$n_match<br />";
  11285. */
  11286. if (ATTACK_DETECTION_MANY_URLS > 0)
  11287. if ($n_match >= ATTACK_DETECTION_MANY_URLS)
  11288. {
  11289. $s_attack = "Many URLS in a field";
  11290. $s_info = GetMessage(MSG_ATTACK_MANYURL_INFO,
  11291. array("FLD"=>$s_fld,"NUM"=>($n_match)),false);
  11292. $s_user_info = GetMessage(MSG_USER_ATTACK_MANY_URLS,array(),false);
  11293. return (true);
  11294. }
  11295. if ($n_match > 0)
  11296. $a_fld_names[] = $s_fld;
  11297. }
  11298. }
  11299. if (ATTACK_DETECTION_MANY_URL_FIELDS > 0)
  11300. if (count($a_fld_names) >= ATTACK_DETECTION_MANY_URL_FIELDS)
  11301. {
  11302. $s_attack = "Many fields with URLs";
  11303. $s_info = GetMessage(MSG_ATTACK_MANYFIELDS_INFO,
  11304. array("FLDS"=>implode(",",$a_fld_names),
  11305. "NUM"=>(count($a_fld_names))),false);
  11306. $s_user_info = GetMessage(MSG_USER_ATTACK_MANY_URL_FIELDS,array(),false);
  11307. return (true);
  11308. }
  11309. return (false);
  11310. }
  11311. function IsAjax()
  11312. {
  11313. global $SPECIAL_VALUES,$aFormVars,$aGetVars;
  11314. //
  11315. // this may be called too early to have SPECIAL_VALUES loaded,
  11316. // so we check the submitted form vars too.
  11317. //
  11318. if ($SPECIAL_VALUES["fmmode"] == "ajax")
  11319. return (true);
  11320. if (isset($aFormVars["fmmode"]))
  11321. return ($aFormVars["fmmode"] == "ajax");
  11322. if (isset($aGetVars["fmmode"]))
  11323. return ($aGetVars["fmmode"] == "ajax");
  11324. return (false);
  11325. }
  11326. //
  11327. // Detect annoying attacks and prevent them from sending spurious
  11328. // alert messages.
  11329. //
  11330. function DetectAttacks($a_fields)
  11331. {
  11332. global $ATTACK_DETECTION_DUPS,$ATTACK_DETECTION_REVERSE_CAPTCHA;
  11333. $s_info = $s_attack = "";
  11334. $b_attacked = false;
  11335. $s_user_info = "";
  11336. if (ATTACK_DETECTION_MIME)
  11337. if (DetectMimeAttack($a_fields,$s_attack,$s_info,$s_user_info))
  11338. $b_attacked = true;
  11339. if (!$b_attacked && !empty($ATTACK_DETECTION_DUPS))
  11340. if (DetectDupAttack($a_fields,$s_attack,$s_info,$s_user_info))
  11341. $b_attacked = true;
  11342. if (!$b_attacked && ATTACK_DETECTION_SPECIALS)
  11343. if (DetectSpecialsAttack($a_fields,$s_attack,$s_info,$s_user_info))
  11344. $b_attacked = true;
  11345. if (!$b_attacked && (ATTACK_DETECTION_MANY_URLS ||
  11346. ATTACK_DETECTION_MANY_URL_FIELDS))
  11347. if (DetectManyURLsAttack($a_fields,$s_attack,$s_info,$s_user_info))
  11348. $b_attacked = true;
  11349. if (ATTACK_DETECTION_JUNK)
  11350. if (DetectJunkAttack($a_fields,$s_attack,$s_info,$s_user_info))
  11351. $b_attacked = true;
  11352. if (!$b_attacked && !empty($ATTACK_DETECTION_REVERSE_CAPTCHA))
  11353. if (DetectRevCaptchaAttack($ATTACK_DETECTION_REVERSE_CAPTCHA,$a_fields,$s_attack,$s_info,$s_user_info))
  11354. $b_attacked = true;
  11355. if ($b_attacked)
  11356. {
  11357. if (function_exists('FMHookAttacked'))
  11358. FMHookAttacked(''); /* in the future, pass the type of attack */
  11359. if (ALERT_ON_ATTACK_DETECTION)
  11360. SendAlert(GetMessage(MSG_ATTACK_DETECTED,
  11361. array("ATTACK"=>$s_attack,
  11362. "INFO"=>$s_info,)),
  11363. false);
  11364. if (!IsAjax() && ATTACK_DETECTION_URL !== "")
  11365. Redirect(ATTACK_DETECTION_URL,GetMessage(MSG_FORM_ERROR));
  11366. else
  11367. {
  11368. global $SERVER;
  11369. CreatePage(GetMessage(MSG_ATTACK_PAGE,array("SERVER"=>$SERVER,"USERINFO"=>$s_user_info)),
  11370. GetMessage(MSG_FORM_ERROR));
  11371. }
  11372. exit;
  11373. }
  11374. }
  11375. //
  11376. // Implement reverse captcha. At least two fields must be provided.
  11377. // At least one of the fields should have a non-empty value.
  11378. //
  11379. function DetectRevCaptchaAttack($a_revcap_spec,$a_form_data,&$s_attack,&$s_info,&$s_user_info)
  11380. {
  11381. global $bReverseCaptchaCompleted;
  11382. if (count($a_revcap_spec) < 2)
  11383. {
  11384. SendAlert(GetMessage(MSG_REV_CAP));
  11385. return (false);
  11386. }
  11387. //
  11388. // check the reverse captcha fields
  11389. //
  11390. $n_empty = $n_non_empty = 0;
  11391. $b_attacked = false;
  11392. $s_info = "";
  11393. foreach ($a_revcap_spec as $s_fld_name=>$s_value)
  11394. {
  11395. if ($s_value === "")
  11396. {
  11397. $n_empty++;
  11398. if (isset($a_form_data[$s_fld_name]) &&
  11399. $a_form_data[$s_fld_name] !== "")
  11400. {
  11401. $b_attacked = true;
  11402. $s_info .= "\n".GetMessage(MSG_ATTACK_REV_CAP_INFO,
  11403. array("FLD"=>$s_fld_name,
  11404. "CONTENT"=>$a_form_data[$s_fld_name]),false);
  11405. }
  11406. }
  11407. else
  11408. {
  11409. $n_non_empty++;
  11410. if (!isset($a_form_data[$s_fld_name]) ||
  11411. $a_form_data[$s_fld_name] !== $s_value)
  11412. {
  11413. $b_attacked = true;
  11414. $s_info .= "\n".GetMessage(MSG_ATTACK_REV_CAP_INFO,
  11415. array("FLD"=>$s_fld_name,
  11416. "CONTENT"=>
  11417. isset($a_form_data[$s_fld_name]) ?
  11418. $a_form_data[$s_fld_name] :
  11419. ""),false);
  11420. }
  11421. }
  11422. }
  11423. //
  11424. // check that the rev captcha specification is correct:
  11425. // at least two fields, at least one empty
  11426. // and at least one non-empty
  11427. //
  11428. if ($n_empty + $n_non_empty < 2 ||
  11429. $n_empty == 0 || $n_non_empty == 0)
  11430. {
  11431. SendAlert(GetMessage(MSG_REV_CAP));
  11432. return (false);
  11433. }
  11434. if ($b_attacked)
  11435. {
  11436. $s_attack = "Reverse Captcha";
  11437. $s_user_info = GetMessage(MSG_USER_ATTACK_REV_CAP,array(),false);
  11438. }
  11439. $bReverseCaptchaCompleted = !$b_attacked;
  11440. //FMDebug("RevCaptcha done: ".($bReverseCaptchaCompleted ? "success" : "failure"));
  11441. return ($b_attacked);
  11442. }
  11443. //
  11444. // Check whether a form submission is allowed based on any Captcha provided
  11445. //
  11446. function CheckCaptchaSubmit()
  11447. {
  11448. global $SPECIAL_VALUES,$reCaptchaProcessor;
  11449. if ($SPECIAL_VALUES["imgverify"] !== "")
  11450. {
  11451. //
  11452. // implement reCaptcha
  11453. //
  11454. if (isset($reCaptchaProcessor))
  11455. {
  11456. if (!$reCaptchaProcessor->Check($SPECIAL_VALUES["imgverify"],$SPECIAL_VALUES,$s_error))
  11457. UserError("recaptcha",GetMessage(MSG_RECAPTCHA_MATCH,array("ERR"=>$s_error)));
  11458. }
  11459. //
  11460. // implement other CAPTCHA
  11461. //
  11462. else
  11463. {
  11464. //
  11465. // VerifyImgString is from Tectite's simple verifyimg.php CAPTCHA
  11466. // turing_string is from Captcha Creator
  11467. //
  11468. if (!IsSetSession("VerifyImgString") &&
  11469. !IsSetSession("turing_string"))
  11470. ErrorWithIgnore("verify_failed",GetMessage(MSG_VERIFY_MISSING),false);
  11471. //
  11472. // the user's entry must match the value in the session; allow
  11473. // spaces in the user's input
  11474. //
  11475. if (IsSetSession("VerifyImgString"))
  11476. {
  11477. if (strtoupper(str_replace(" ","",$SPECIAL_VALUES["imgverify"])) !==
  11478. strtoupper(GetSession("VerifyImgString")))
  11479. UserError("img_verify",GetMessage(MSG_VERIFY_MATCH));
  11480. }
  11481. else
  11482. {
  11483. if (strtoupper(str_replace(" ","",$SPECIAL_VALUES["imgverify"])) !==
  11484. strtoupper(GetSession("turing_string")))
  11485. UserError("img_verify",GetMessage(MSG_VERIFY_MATCH)/*,
  11486. "imgverify='".$SPECIAL_VALUES["imgverify"]."' ".
  11487. "turing_string='".GetSession("turing_string")."'"*/);
  11488. }
  11489. }
  11490. }
  11491. }
  11492. /*
  11493. * Class: AutoResponder
  11494. * Description:
  11495. * Implements the auto responding feature of FormMail.
  11496. * The object must only be created after special fields have been
  11497. * processed.
  11498. */
  11499. class AutoResponder
  11500. {
  11501. var $_bRequested; // true if requested by the form
  11502. var $_sTo; // to-address for auto response
  11503. var $_sSubject; // subject for auto response
  11504. var $_iNone = 0; // must be zero - initializes iType and iCaptchaType
  11505. var $_iCaptchaType; // type of CAPTCHA that's been successfully processed
  11506. var $_bCaptchaOK; // true if CAPTCHA processing is OK, otherwise false
  11507. //
  11508. // values of _iCaptchaType
  11509. //
  11510. var $_iFull = 1; // full captcha
  11511. var $_iRev = 2; // reverse captcha
  11512. var $_iType; // type of autoresponse (template or plain)
  11513. //
  11514. // values of _iType
  11515. //
  11516. var $_iSendTemplate = 1; // send a template
  11517. var $_iSendPlain = 2; // send a plain file
  11518. /*
  11519. * Method: AutoResponder ctor
  11520. * Parameters: void
  11521. * Returns: n/a
  11522. * Description:
  11523. * Constructs the object.
  11524. */
  11525. function AutoResponder()
  11526. {
  11527. global $SPECIAL_VALUES;
  11528. $this->_bCaptchaOK = $this->_bRequested = false;
  11529. $this->_sTo = "";
  11530. $this->_sSubject = "";
  11531. $this->_iType = $this->_iNone;
  11532. $this->_iCaptchaType = $this->_iNone;
  11533. //
  11534. // An autoreponse is sometimes optional in the sense the user
  11535. // can choose whether they want it.
  11536. // It can also be mandatory, and enforced by the form owner.
  11537. // Here are the rules:
  11538. // 1. If there is no return email address (email field), no autoresponse.
  11539. // In this case, if autoresponse has been requested by the form, send
  11540. // an alert message to the form owner, but otherwise ignore the problem
  11541. // (it's optional).
  11542. // 2. If no autoresponse has been requested by the form, skip.
  11543. // 3. If HTMLTemplate or PlainTemplate is set:
  11544. // 3a. If full CAPTCHA has been performed, send autoresponse.
  11545. // 3b If no full CAPTCHA has been performed, no autoresponse.
  11546. // 4. If HTMLTemplate and PlainTemplate are *not* set and either
  11547. // PlainFile or HTMLFile is set:
  11548. // 4a. If full CAPTCHA has been performed, send autoresponse.
  11549. // 4b. If Reverse CAPTCHA has been performed, send autoresponse.
  11550. // 4c. Otherwise, no autoresponse.
  11551. // 5. If full CAPTCHA is attempted but fails (e.g. wrong input), display
  11552. // error.
  11553. //
  11554. // The form owner can enforce autoresponse by making "email" required,
  11555. // and making "arverify" or "recaptcha_response_field" required (for templates)
  11556. // or by ensuring Reverse CAPTCHA is performed (for PlainFile or HTMLFile).
  11557. //
  11558. if (IsAROptionSet('HTMLTemplate') ||
  11559. IsAROptionSet('PlainTemplate'))
  11560. $this->_iType = $this->_iSendTemplate;
  11561. if (IsAROptionSet('PlainFile') ||
  11562. IsAROptionSet('HTMLFile'))
  11563. $this->_iType = $this->_iSendPlain;
  11564. if ($this->_iType)
  11565. {
  11566. //
  11567. // the form has requested autoresponse....
  11568. // we need an email address to send to
  11569. //
  11570. if (!isset($SPECIAL_VALUES["email"]) || empty($SPECIAL_VALUES["email"]))
  11571. SendAlert(GetMessage(MSG_ARESP_EMAIL));
  11572. else
  11573. {
  11574. $this->_bRequested = true;
  11575. $this->_sTo = $SPECIAL_VALUES["email"];
  11576. if (IsAROptionSet('Subject'))
  11577. $this->_sSubject = GetAROption('Subject');
  11578. else
  11579. $this->_sSubject = GetMessage(MSG_ARESP_SUBJ,array(),false);
  11580. }
  11581. }
  11582. }
  11583. /*
  11584. * Method: AutoResponder::IsRequested
  11585. * Parameters: void
  11586. * Returns: bool true if autoresponding has been requested
  11587. * Description:
  11588. * Determines if autoresponding has been requested by the HTML.
  11589. */
  11590. function IsRequested()
  11591. {
  11592. return ($this->_bRequested);
  11593. }
  11594. /*
  11595. * Method: AutoResponder::Process
  11596. * Parameters: $b_check_only if true, perform checks but do not send
  11597. * Returns: void
  11598. * Description:
  11599. * Processes the autorespond.
  11600. */
  11601. function Process($b_check_only = false)
  11602. {
  11603. global $SPECIAL_VALUES;
  11604. FMDebug("AutoResponder::Process: check=".($b_check_only ? "Y" : "N"));
  11605. if ($this->IsRequested())
  11606. {
  11607. FMDebug("AutoResponder::Process: requested");
  11608. //
  11609. // verify CAPTCHA or that Reverse CAPTCHA has been completed
  11610. // (unless we've already done that)
  11611. //
  11612. $this->_CheckCaptcha();
  11613. if (!$b_check_only && $this->_bCaptchaOK)
  11614. {
  11615. FMDebug("AutoResponder::Process: proceeding, type=".$this->_iType);
  11616. //
  11617. // for a template, full CAPTCHA must have been processed
  11618. //
  11619. if ($this->_iType == $this->_iSendTemplate)
  11620. {
  11621. if ($this->_iCaptchaType == $this->_iFull)
  11622. $this->_Send(true);
  11623. }
  11624. //
  11625. // for a plain file, reverse CAPTCHA is sufficient, any CAPTCHA is OK
  11626. //
  11627. elseif ($this->_iType == $this->_iSendPlain)
  11628. if ($this->_iCaptchaType)
  11629. $this->_Send(false);
  11630. }
  11631. }
  11632. }
  11633. /*
  11634. * Method: AutoResponder::_CheckCaptcha
  11635. * Parameters: void
  11636. * Returns: void
  11637. * Description:
  11638. * Checks the type of CAPTCHA that has been processed.
  11639. * This method should only be called if autoresponse has been requested
  11640. * by the form (i.e. IsRequested returns true).
  11641. */
  11642. function _CheckCaptcha()
  11643. {
  11644. global $SPECIAL_VALUES,$bReverseCaptchaCompleted,$ATTACK_DETECTION_REVERSE_CAPTCHA;
  11645. global $reCaptchaProcessor;
  11646. //
  11647. // only check for CAPTCHA once
  11648. //
  11649. if (!$this->_iCaptchaType)
  11650. {
  11651. //
  11652. // check for full CAPTCHA attempt
  11653. // first, check for reCaptcha
  11654. //
  11655. if (isset($reCaptchaProcessor) && $SPECIAL_VALUES["arverify"] !== "")
  11656. {
  11657. $this->_iCaptchaType = $this->_iFull;
  11658. if ($reCaptchaProcessor->Check($SPECIAL_VALUES["arverify"],$SPECIAL_VALUES,$s_error))
  11659. $this->_bCaptchaOK = true;
  11660. else
  11661. {
  11662. $this->_bCaptchaOK = false;
  11663. //
  11664. // report the error
  11665. //
  11666. WriteARLog($this->_sTo,$this->_sSubject,
  11667. GetMessage(MSG_LOG_RECAPTCHA,array("ERR"=>$s_error),false));
  11668. UserError("recaptcha",GetMessage(MSG_RECAPTCHA_MATCH,array("ERR"=>$s_error)));
  11669. }
  11670. }
  11671. //
  11672. // now check for our verifyimg or Captcha Creator
  11673. //
  11674. elseif ($SPECIAL_VALUES["arverify"] !== "")
  11675. {
  11676. //
  11677. // allow spaces in the user's input, except for reCaptcha
  11678. //
  11679. $s_arverify = str_replace(" ","",$SPECIAL_VALUES["arverify"]);
  11680. $this->_iCaptchaType = $this->_iFull;
  11681. //
  11682. // full CAPTCHA has been attempted
  11683. // VerifyImgString is from Tectite's simple verifyimg.php CAPTCHA.
  11684. // turing_string is from Captcha Creator
  11685. //
  11686. if (IsSetSession("VerifyImgString") || IsSetSession("turing_string"))
  11687. {
  11688. $b_match = false;
  11689. //
  11690. // the user's entry must match the value in the session
  11691. //
  11692. if (IsSetSession("VerifyImgString"))
  11693. {
  11694. if (strtoupper($s_arverify) === strtoupper(GetSession("VerifyImgString")))
  11695. $b_match = true;
  11696. }
  11697. else
  11698. {
  11699. if (strtoupper($s_arverify) === strtoupper(GetSession("turing_string")))
  11700. $b_match = true;
  11701. }
  11702. if ($b_match)
  11703. $this->_bCaptchaOK = true;
  11704. else
  11705. {
  11706. WriteARLog($this->_sTo,$this->_sSubject,
  11707. GetMessage(MSG_LOG_NO_MATCH,array(),false));
  11708. UserError("ar_verify",GetMessage(MSG_ARESP_NO_MATCH));
  11709. }
  11710. }
  11711. else
  11712. {
  11713. //
  11714. // ...and it has failed because there's no session data
  11715. //
  11716. WriteARLog($this->_sTo,$this->_sSubject,
  11717. GetMessage(MSG_LOG_NO_VERIMG,array(),false));
  11718. ErrorWithIgnore("verify_failed",GetMessage(MSG_ARESP_NO_AUTH),true);
  11719. }
  11720. }
  11721. elseif (ENABLE_ATTACK_DETECTION && !empty($ATTACK_DETECTION_REVERSE_CAPTCHA))
  11722. {
  11723. //
  11724. // Reverse CAPTCHA has been configured
  11725. //
  11726. $this->_iCaptchaType = $this->_iRev;
  11727. $this->_bCaptchaOK = $bReverseCaptchaCompleted;
  11728. }
  11729. }
  11730. }
  11731. /*
  11732. * Method: AutoResponder::_Send
  11733. * Parameters: $b_use_template if true, allow template, otherwise file
  11734. * Returns: void
  11735. * Description:
  11736. * Sends an autoreponse using a template.
  11737. */
  11738. function _Send($b_use_template)
  11739. {
  11740. global $SPECIAL_VALUES,$HOOK_DIR;
  11741. //
  11742. // declare some global vars for the hook system calls below
  11743. //
  11744. global $aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues,$aFileVars;
  11745. FMDebug("Sending auto response: ".($b_use_template ? "template" : "plain"));
  11746. //
  11747. // Hook system: before sending auto response
  11748. //
  11749. if ($HOOK_DIR !== "")
  11750. {
  11751. if (!@include("$HOOK_DIR/fmhookprearesp.inc.php"))
  11752. @include("$HOOK_DIR/fmhookprearesp.inc");
  11753. }
  11754. if (!$this->_SendEmail($this->_sTo,$this->_sSubject,$aRawDataValues,$b_use_template))
  11755. {
  11756. WriteARLog($this->_sTo,$this->_sSubject,
  11757. GetMessage(MSG_LOG_FAILED,array(),false));
  11758. SendAlert(GetMessage(MSG_ARESP_FAILED));
  11759. }
  11760. else
  11761. {
  11762. WriteARLog($this->_sTo,$this->_sSubject,
  11763. GetMessage(MSG_LOG_OK,array(),false));
  11764. //
  11765. // Hook system: after sending auto response
  11766. //
  11767. if ($HOOK_DIR !== "")
  11768. if (!@include("$HOOK_DIR/fmhookpostaresp.inc.php"))
  11769. @include("$HOOK_DIR/fmhookpostaresp.inc");
  11770. }
  11771. }
  11772. /*
  11773. * Method: AutoResponder::_SendEmail
  11774. * Parameters: $s_to the email address to send to
  11775. * $s_subj the subject line
  11776. * $a_values field values to access
  11777. * $b_use_template if true, use a template, otherwise plain file
  11778. * Returns: bool true on success, otherwise false
  11779. * Description:
  11780. * Sends an autoresponse email to the user.
  11781. */
  11782. function _SendEmail($s_to,$s_subj,$a_values,$b_use_template)
  11783. {
  11784. global $aPHPVERSION,$SPECIAL_VALUES,$FROM_USER;
  11785. //
  11786. // need PHP 4.0.5 for the preg_replace_callback function
  11787. //
  11788. if (!IsPHPAtLeast("4.0.5"))
  11789. {
  11790. SendAlert(GetMessage(MSG_PHP_AUTORESP,
  11791. array("PHPVERS"=>implode(".",$aPHPVERSION))));
  11792. return (false);
  11793. }
  11794. $a_headers = array();
  11795. $s_mail_text = "";
  11796. $s_from_addr = GetAROption("FromAddr");
  11797. if (!isset($s_from_addr))
  11798. {
  11799. $s_from_addr = "";
  11800. if (isset($FROM_USER) && !empty($FROM_USER))
  11801. {
  11802. if ($FROM_USER != "NONE")
  11803. $s_from_addr = $FROM_USER;
  11804. }
  11805. else
  11806. {
  11807. global $SERVER;
  11808. $s_from_addr = "FormMail@".$SERVER;
  11809. }
  11810. }
  11811. else
  11812. $s_from_addr = UnMangle($s_from_addr);
  11813. if (!empty($s_from_addr))
  11814. $a_headers['From'] = SafeHeader($s_from_addr);
  11815. $s_type = "";
  11816. if ($b_use_template)
  11817. {
  11818. if (IsAROptionSet('PlainTemplate'))
  11819. {
  11820. $s_type .= "PlainTemplate ";
  11821. $s_template = GetAROption("PlainTemplate");
  11822. if (!ProcessTemplate($s_template,$a_lines,$a_values,
  11823. GetAROption('TemplateMissing'),
  11824. 'SubstituteValuePlain'))
  11825. return (false);
  11826. FMDebug("AutoRespond: PlainTemplate ".count($a_lines)." lines");
  11827. $s_mail_text = implode(BODY_LF,$a_lines);
  11828. }
  11829. if (IsAROptionSet("HTMLTemplate"))
  11830. {
  11831. $s_type .= "HTMLTemplate ";
  11832. if (!MakeMimeMail($s_mail_text,$a_headers,$a_values,
  11833. GetAROption("HTMLTemplate"),
  11834. GetAROption('TemplateMissing')))
  11835. return (false);
  11836. FMDebug("AutoRespond: HTMLTemplate ".strlen($s_mail_text)." bytes");
  11837. }
  11838. }
  11839. else
  11840. {
  11841. global $TEMPLATEURL,$TEMPLATEDIR;
  11842. if (IsAROptionSet('PlainFile'))
  11843. {
  11844. $s_type .= "PlainFile ";
  11845. //
  11846. // load the plain text file from the templates area
  11847. //
  11848. if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
  11849. {
  11850. SendAlert(GetMessage(MSG_TEMPLATES));
  11851. return (false);
  11852. }
  11853. $s_file = GetAROption("PlainFile");
  11854. if (($a_lines = LoadTemplate($s_file,$TEMPLATEDIR,$TEMPLATEURL,true)) === false)
  11855. return (false);
  11856. $s_mail_text = implode(BODY_LF,$a_lines);
  11857. FMDebug("AutoRespond: PlainFile ".count($a_lines)." lines");
  11858. }
  11859. if (IsAROptionSet("HTMLFile"))
  11860. {
  11861. $s_type .= "HTMLFile ";
  11862. if (!MakeMimeMail($s_mail_text,$a_headers,$a_values,
  11863. GetAROption("HTMLFile"),"",
  11864. false,"",array(),array(),false))
  11865. return (false);
  11866. FMDebug("AutoRespond: HTMLTemplate ".strlen($s_mail_text)." bytes");
  11867. }
  11868. }
  11869. if (strlen($s_mail_text) == 0)
  11870. SendAlert(GetMessage(MSG_ARESP_EMPTY),array("TYPE"=>$s_type));
  11871. FMDebug("AutoRespond: message is ".strlen($s_mail_text)." bytes");
  11872. return (SendCheckedMail($s_to,$s_subj,$s_mail_text,$s_from_addr,$a_headers));
  11873. }
  11874. }
  11875. /*
  11876. * Class: SessionAccess
  11877. * Description:
  11878. * Implements access to the general PHP session.
  11879. * This provides a secure way of copy data to and from the
  11880. * user's PHP session.
  11881. */
  11882. class SessionAccess
  11883. {
  11884. var $_aAccessList;
  11885. /*
  11886. * Method: SessionAccess ctor
  11887. * Parameters: $a_access_list list of variables that can be accessed
  11888. * Returns: n/a
  11889. * Description:
  11890. * Constructs the object.
  11891. */
  11892. function SessionAccess($a_access_list)
  11893. {
  11894. $this->_aAccessList = $a_access_list;
  11895. }
  11896. /*
  11897. * Method: SessionAccess::CopyIn
  11898. * Parameters: $a_vars reference to an array of values (keyed on name)
  11899. * $b_overwrite_empty if true, the session value will overwrite
  11900. * an empty array variable
  11901. * Returns: int number of values copied
  11902. * Description:
  11903. * Copies in the list of variables from the session to the given array.
  11904. */
  11905. function CopyIn(&$a_vars,$b_overwrite_empty)
  11906. {
  11907. //$s_db = "Session CopyIn:\n";
  11908. $n_copied = 0;
  11909. foreach ($this->_aAccessList as $s_var_name)
  11910. if (IsSetSession($s_var_name))
  11911. if (!isset($a_vars[$s_var_name]) ||
  11912. ($b_overwrite_empty &&
  11913. FieldManager::IsEmpty($a_vars[$s_var_name])))
  11914. {
  11915. $a_vars[$s_var_name] = GetSession($s_var_name);
  11916. //$s_db .= "$s_var_name='".$a_vars[$s_var_name]."'\n";
  11917. $n_copied++;
  11918. };
  11919. //SendAlert($s_db);
  11920. return ($n_copied);
  11921. }
  11922. /*
  11923. * Method: SessionAccess::CopyOut
  11924. * Parameters: $a_vars reference to an array of values (keyed on name)
  11925. * $a_fields an array of fields to copy
  11926. * Returns: int number of values copied
  11927. * Description:
  11928. * Copies the variables from the given array into the session.
  11929. * The list of fields to copy is specified in _aAccessList.
  11930. * If $a_fields is provided, it contains a list of fields to copy, which
  11931. * limits the fields selected from _aAccessList, otherwise all fields
  11932. * listed in _aAccessList are copied.
  11933. */
  11934. function CopyOut(&$a_vars,$a_fields = array())
  11935. {
  11936. //$s_db = "Session CopyOut:\n";
  11937. $n_copied = 0;
  11938. foreach ($this->_aAccessList as $s_var_name)
  11939. if (isset($a_vars[$s_var_name]))
  11940. if (empty($a_fields) || in_array($s_var_name,$a_fields))
  11941. {
  11942. SetSession($s_var_name,$a_vars[$s_var_name]);
  11943. //$s_db .= "$s_var_name='".GetSession($s_var_name)."'\n";
  11944. $n_copied++;
  11945. };
  11946. //SendAlert($s_db);
  11947. return ($n_copied);
  11948. }
  11949. };
  11950. $SessionAccessor = new SessionAccess($SESSION_ACCESS);
  11951. $bAdvTemplates = false;
  11952. if (ADVANCED_TEMPLATES &&
  11953. (!empty($TEMPLATEDIR) || !empty($TEMPLATEURL) ||
  11954. !empty($MULTIFORMDIR) || !empty($MULTIFORMURL)))
  11955. $bAdvTemplates = true;
  11956. if (isset($aGetVars["return"]) && is_numeric($aGetVars["return"]))
  11957. {
  11958. //
  11959. // if advanced templates are in use, we will need them for
  11960. // performing a multi-page form return
  11961. //
  11962. if ($bAdvTemplates)
  11963. {
  11964. $FMCTEMPLATE_PROC = true;
  11965. if (!include_once("$MODULEDIR/$FMCOMPUTE"))
  11966. Error("load_fmcompute",GetMessage(MSG_LOAD_FMCOMPUTE,
  11967. array("FILE"=>"$MODULEDIR/$FMCOMPUTE",
  11968. "ERROR"=>$php_errormsg)),false,false);
  11969. }
  11970. MultiFormReturn($aGetVars["return"]);
  11971. exit;
  11972. }
  11973. //
  11974. // Hook system: after initialization
  11975. //
  11976. if ($HOOK_DIR !== "")
  11977. if (!@include("$HOOK_DIR/fmhookpostinit.inc.php"))
  11978. @include("$HOOK_DIR/fmhookpostinit.inc");
  11979. //
  11980. // check configuration values for potential security problems
  11981. //
  11982. CheckConfig();
  11983. //
  11984. // otherwise, do the real processing of FormMail
  11985. //
  11986. $aStrippedFormVars = $aAllRawValues = StripGPCArray($aFormVars);
  11987. if (ENABLE_ATTACK_DETECTION)
  11988. DetectAttacks($aAllRawValues);
  11989. //
  11990. // Copy in configured session variables, overwriting any
  11991. // fields that are empty.
  11992. //
  11993. $SessionAccessor->CopyIn($aAllRawValues,true);
  11994. $SessionAccessor->CopyIn($aStrippedFormVars,true);
  11995. //
  11996. // process the options
  11997. //
  11998. ProcessMailOptions($aAllRawValues);
  11999. ProcessCRMOptions($aAllRawValues);
  12000. ProcessAROptions($aAllRawValues);
  12001. ProcessFilterOptions($aAllRawValues);
  12002. //
  12003. // create any derived fields
  12004. // NOTE: it's important that derivation occurs before cleaned values
  12005. // are created. If derivation occurred after cleaning or it created
  12006. // fields that were assumed to be clean, then an attack could create
  12007. // forged email headers using derive_fields. The code is safe with
  12008. // the logic sequence below.
  12009. //
  12010. $aAllRawValues = CreateDerived($aAllRawValues);
  12011. list($aFieldOrder,$aCleanedValues,$aRawDataValues) = ParseInput($aAllRawValues);
  12012. FilterFiles($aFileVars);
  12013. //
  12014. // if we're processing multi-forms, then merge in the raw data from previous
  12015. // forms unless this is the first page of the form sequence
  12016. //
  12017. if (IsSetSession("FormList") && $SPECIAL_VALUES["multi_start"] != 1)
  12018. {
  12019. list($aFieldOrder,$aCleanedValues,
  12020. $aRawDataValues,$aAllRawValues,$aFileVars) = GetMultiValues(
  12021. GetSession("FormList"),
  12022. GetSession("FormIndex"),
  12023. $aFieldOrder,$aCleanedValues,
  12024. $aRawDataValues,$aAllRawValues,
  12025. $aFileVars);
  12026. }
  12027. if ($SPECIAL_VALUES["file_names"] !== "")
  12028. list($aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues,$aFileVars) =
  12029. SetFileNames($SPECIAL_VALUES["file_names"],$aFieldOrder,
  12030. $aCleanedValues,$aRawDataValues,$aAllRawValues,$aFileVars);
  12031. //
  12032. // Hook system: after loading and processing data
  12033. //
  12034. if ($HOOK_DIR !== "")
  12035. if (!@include("$HOOK_DIR/fmhookload.inc.php"))
  12036. @include("$HOOK_DIR/fmhookload.inc");
  12037. if ($FORM_INI_FILE !== "")
  12038. {
  12039. ProcessFormIniFile($FORM_INI_FILE);
  12040. //
  12041. // Hook system: after processing INI file
  12042. //
  12043. if ($HOOK_DIR !== "")
  12044. if (!@include("$HOOK_DIR/fmhookinifile.inc.php"))
  12045. @include("$HOOK_DIR/fmhookinifile.inc");
  12046. }
  12047. $bDoneSomething = false;
  12048. if (DB_SEE_INPUT)
  12049. {
  12050. /***
  12051. echo "<pre>";
  12052. print_r($aFormVars);
  12053. print_r($aServerVars);
  12054. echo "</pre>";
  12055. exit;
  12056. ****/
  12057. CreatePage(implode("\n",$FORMATTED_INPUT),"Debug Output - Fields Submitted");
  12058. ZapSession();
  12059. exit;
  12060. }
  12061. if (!empty($SPECIAL_VALUES["fmcompute"]) || $bAdvTemplates)
  12062. {
  12063. $FM_UserErrors = array();
  12064. //
  12065. // Generalized interface between FMCompute and FormMail functions
  12066. //
  12067. function FM_CallFunction($s_func,$a_params,&$m_return,
  12068. &$s_mesg,&$a_debug,&$a_alerts)
  12069. {
  12070. switch ($s_func)
  12071. {
  12072. case "FMFatalError":
  12073. SendComputeAlerts();
  12074. if (count($a_params) < 3)
  12075. Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  12076. array("FUNC"=>$s_func,
  12077. "COUNT"=>count($a_params))),
  12078. false,false);
  12079. else
  12080. Error("fmcompute_error",$a_params[0],$a_params[1],$a_params[2]);
  12081. break;
  12082. case "FMFatalUserError":
  12083. SendComputeAlerts();
  12084. if (count($a_params) < 1)
  12085. Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  12086. array("FUNC"=>$s_func,
  12087. "COUNT"=>count($a_params))),
  12088. false,false);
  12089. else
  12090. UserError("fmcompute_usererror",$a_params[0]);
  12091. break;
  12092. case "FMUserError":
  12093. if (count($a_params) < 1)
  12094. {
  12095. SendComputeAlerts();
  12096. Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  12097. array("FUNC"=>$s_func,
  12098. "COUNT"=>count($a_params))),
  12099. false,false);
  12100. }
  12101. else
  12102. {
  12103. global $FM_UserErrors;
  12104. $FM_UserErrors[] = $a_params[0];
  12105. }
  12106. break;
  12107. case "FMSaveAllFilesToRepository":
  12108. if (count($a_params) != 0)
  12109. {
  12110. SendComputeAlerts();
  12111. Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  12112. array("FUNC"=>$s_func,
  12113. "COUNT"=>count($a_params))),
  12114. false,false);
  12115. }
  12116. else
  12117. $m_return = SaveAllFilesToRepository();
  12118. break;
  12119. case "FMDeleteFileFromRepository":
  12120. if (count($a_params) != 1)
  12121. {
  12122. SendComputeAlerts();
  12123. Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  12124. array("FUNC"=>$s_func,
  12125. "COUNT"=>count($a_params))),
  12126. false,false);
  12127. }
  12128. else
  12129. $m_return = DeleteFileFromRepository($a_params[0]);
  12130. break;
  12131. case "FMNextNum":
  12132. if (count($a_params) != 2)
  12133. {
  12134. SendComputeAlerts();
  12135. Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
  12136. array("FUNC"=>$s_func,
  12137. "COUNT"=>count($a_params))),
  12138. false,false);
  12139. }
  12140. else
  12141. {
  12142. $i_pad = $a_params[0];
  12143. $i_base = $a_params[1];
  12144. if ($i_base < 2 || $i_base > 36)
  12145. Error("fmcompute_call",GetMessage(MSG_CALL_INVALID_PARAM,
  12146. array("FUNC"=>$s_func,
  12147. "PARAM"=>2,
  12148. "CORRECT"=>2...36)),
  12149. false,false);
  12150. $m_return = GetNextNum($i_pad,$i_base);
  12151. }
  12152. break;
  12153. default:
  12154. $s_mesg = GetMessage(MSG_CALL_UNK_FUNC,array("FUNC"=>$s_func));
  12155. return (false);
  12156. }
  12157. return (true);
  12158. }
  12159. //
  12160. // register useful FormMail functions with FMCompute module
  12161. //
  12162. function RegisterFormMailFunctions(&$fmc)
  12163. {
  12164. //
  12165. // Allows the user to call "Error" from within a computation
  12166. //
  12167. if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
  12168. "FMFatalError",
  12169. array("string","bool","bool"),
  12170. "FM_CallFunction")) !== true)
  12171. Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  12172. array("FUNC"=>"FMFatalError",
  12173. "ERROR"=>$s_msg)),false,false);
  12174. //
  12175. // Allows the user to call "UserError" from within a computation
  12176. //
  12177. if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
  12178. "FMFatalUserError",
  12179. array("string"),
  12180. "FM_CallFunction")) !== true)
  12181. Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  12182. array("FUNC"=>"FMFatalUserError",
  12183. "ERROR"=>$s_msg)),false,false);
  12184. //
  12185. // Allows the user to record an error to be displayed
  12186. // from within a computation.
  12187. //
  12188. if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
  12189. "FMUserError",
  12190. array("string"),
  12191. "FM_CallFunction")) !== true)
  12192. Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  12193. array("FUNC"=>"FMUserError",
  12194. "ERROR"=>$s_msg)),false,false);
  12195. //
  12196. // Saves files to the repository.
  12197. //
  12198. if (($s_msg = $fmc->RegisterExternalFunction("PHP","bool",
  12199. "FMSaveAllFilesToRepository",
  12200. array(),
  12201. "FM_CallFunction")) !== true)
  12202. Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  12203. array("FUNC"=>"FMSaveAllFilesToRepository",
  12204. "ERROR"=>$s_msg)),false,false);
  12205. //
  12206. // Delete a file from the repository.
  12207. //
  12208. if (($s_msg = $fmc->RegisterExternalFunction("PHP","bool",
  12209. "FMDeleteFileFromRepository",
  12210. array("string"),
  12211. "FM_CallFunction")) !== true)
  12212. Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  12213. array("FUNC"=>"FMDeleteFileFromRepository",
  12214. "ERROR"=>$s_msg)),false,false);
  12215. //
  12216. // Generate a Next Number
  12217. //
  12218. if (($s_msg = $fmc->RegisterExternalFunction("PHP","string",
  12219. "FMNextNum",
  12220. array("int","int"),
  12221. "FM_CallFunction")) !== true)
  12222. Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
  12223. array("FUNC"=>"FMNextNum",
  12224. "ERROR"=>$s_msg)),false,false);
  12225. }
  12226. //
  12227. // load the fmcompute module
  12228. //
  12229. if (!empty($SPECIAL_VALUES["fmcompute"]))
  12230. {
  12231. $FMCOMPUTE_CLASS = true;
  12232. $FMCOMPUTE_NODEBUG = true;
  12233. }
  12234. if ($bAdvTemplates)
  12235. $FMCTEMPLATE_PROC = true;
  12236. if (!include_once("$MODULEDIR/$FMCOMPUTE"))
  12237. Error("load_fmcompute",GetMessage(MSG_LOAD_FMCOMPUTE,
  12238. array("FILE"=>"$MODULEDIR/$FMCOMPUTE",
  12239. "ERROR"=>$php_errormsg)),false,false);
  12240. if (!empty($SPECIAL_VALUES["fmcompute"]))
  12241. {
  12242. RegisterFormMailFunctions($FMCalc);
  12243. //
  12244. // if GeoIP support is specified, load that module now
  12245. //
  12246. if (!empty($GEOIP_LIC))
  12247. {
  12248. $FMMODULE_LOAD = true; // signal module load
  12249. if (!include_once("$MODULEDIR/$FMGEOIP"))
  12250. Error("load_module",GetMessage(MSG_LOAD_MODULE,
  12251. array("FILE"=>"$MODULEDIR/$FMGEOIP",
  12252. "ERROR"=>$php_errormsg)),false,false);
  12253. //
  12254. // load the license and register the module
  12255. //
  12256. $GeoIP = new FMGeoIP($GEOIP_LIC);
  12257. if (!$GeoIP->RegisterModule($FMCalc))
  12258. Error("reg_module",GetMessage(MSG_REGISTER_MODULE,
  12259. array("NAME"=>"FMGeoIP",
  12260. "ERROR"=>$GeoIP->GetError())),false,false);
  12261. }
  12262. }
  12263. }
  12264. if (isset($SPECIAL_VALUES["multi_go_back"]) && !empty($SPECIAL_VALUES["multi_go_back"]))
  12265. {
  12266. if (!IsSetSession("FormList") || GetSession("FormIndex") == 0)
  12267. ErrorWithIgnore("go_back",GetMessage(MSG_GO_BACK),false,false);
  12268. MultiKeep(); // store any "multi_keep" data just submitted
  12269. //
  12270. // save back to the session any variables that have been specified in
  12271. // multi_keep
  12272. //
  12273. if (isset($SPECIAL_VALUES["multi_keep"]) && !empty($SPECIAL_VALUES["multi_keep"]))
  12274. $SessionAccessor->CopyOut($aAllRawValues,$SPECIAL_VALUES["multi_keep"]);
  12275. MultiFormReturn(GetSession("FormIndex")-1);
  12276. // echo "Form index = ".GetSession("FormIndex");
  12277. exit;
  12278. }
  12279. //
  12280. // This is the check for spiders; I can't imagine a spider will
  12281. // ever use the POST method.
  12282. //
  12283. if ($bIsGetMethod && count($aFormVars) == 0)
  12284. {
  12285. if (!$ALLOW_GET_METHOD && $bHasGetData)
  12286. CreatePage(GetMessage(MSG_GET_DISALLOWED),GetMessage(MSG_FORM_ERROR));
  12287. else
  12288. CreatePage(GetMessage(MSG_NO_DATA_PAGE),GetMessage(MSG_FORM_ERROR));
  12289. ZapSession();
  12290. exit;
  12291. }
  12292. //
  12293. // Hook system: before performing required and conditions etc.
  12294. //
  12295. if ($HOOK_DIR !== "")
  12296. if (!@include("$HOOK_DIR/fmhookprechecks.inc.php"))
  12297. @include("$HOOK_DIR/fmhookprechecks.inc");
  12298. //
  12299. // check for required fields
  12300. //
  12301. if (!CheckRequired($SPECIAL_VALUES["required"],$aAllRawValues,$sMissing,$aMissingList))
  12302. UserError("missing_fields",GetMessage(MSG_REQD_ERROR),$sMissing,$aMissingList);
  12303. //
  12304. // check complex conditions
  12305. //
  12306. if (!CheckConditions($SPECIAL_VALUES["conditions"],$aAllRawValues,$sMissing,$aMissingList))
  12307. UserError("failed_conditions",GetMessage(MSG_COND_ERROR),$sMissing,$aMissingList);
  12308. //
  12309. // check CAPTCHA
  12310. //
  12311. CheckCaptchaSubmit();
  12312. //
  12313. // Hook system: after performing required and conditions etc.
  12314. //
  12315. if ($HOOK_DIR !== "")
  12316. if (!@include("$HOOK_DIR/fmhookchecks.inc.php"))
  12317. @include("$HOOK_DIR/fmhookchecks.inc");
  12318. if (!empty($SPECIAL_VALUES["fmmodules"]))
  12319. {
  12320. $aModuleList = TrimArray(explode(",",$SPECIAL_VALUES["fmmodules"]));
  12321. $FMMODULE_LOAD = true; // signal module load
  12322. foreach ($aModuleList as $sModule)
  12323. if (!include_once("$MODULEDIR/$sModule"))
  12324. Error("load_module",GetMessage(MSG_LOAD_MODULE,
  12325. array("FILE"=>"$MODULEDIR/$sModule",
  12326. "ERROR"=>$php_errormsg)),false,false);
  12327. }
  12328. if (!empty($SPECIAL_VALUES["fmcompute"]))
  12329. {
  12330. //
  12331. // Callback function for preg_replace_callback to add line
  12332. // numbers on each match
  12333. //
  12334. function AddLineNumbersCallback($a_matches)
  12335. {
  12336. global $iAddLineNumbersCounter;
  12337. return (sprintf("%d:",++$iAddLineNumbersCounter).$a_matches[0]);
  12338. }
  12339. //
  12340. // Add line numbers to some code
  12341. //
  12342. function AddLineNumbers($s_code)
  12343. {
  12344. global $iAddLineNumbersCounter;
  12345. $iAddLineNumbersCounter = 0;
  12346. return (preg_replace_callback('/^/m','AddLineNumbersCallback',$s_code));
  12347. }
  12348. //
  12349. // Load some more code into FMCalc
  12350. //
  12351. function Load($s_code)
  12352. {
  12353. global $FMCalc;
  12354. $a_mesgs = array();
  12355. // echo "Loading '$s_code'";
  12356. if ($FMCalc->Parse($s_code,$a_mesgs) === false)
  12357. {
  12358. $s_msgs = "";
  12359. foreach ($a_mesgs as $a_msg)
  12360. {
  12361. $s_msgs .= "Line ".$a_msg["LINE"];
  12362. $s_msgs .= ", position ".$a_msg["CHAR"].": ";
  12363. $s_msgs .= $a_msg["MSG"]."\n";
  12364. }
  12365. Error("fmcompute_parse",GetMessage(MSG_COMP_PARSE,
  12366. array("CODE"=>AddLineNumbers($s_code),
  12367. "ERRORS"=>$s_msgs)),false,false);
  12368. }
  12369. }
  12370. //
  12371. // Send any alerts found in FMCalc
  12372. //
  12373. function SendComputeAlerts()
  12374. {
  12375. global $FMCalc;
  12376. $a_alerts = $FMCalc->GetAlerts();
  12377. if (count($a_alerts) > 0)
  12378. SendAlert(GetMessage(MSG_COMP_ALERT,
  12379. array("ALERTS"=>implode("\n",StripHTML($a_alerts)))));
  12380. $a_debug = $FMCalc->GetDebug();
  12381. if (count($a_debug) > 0)
  12382. SendAlert(GetMessage(MSG_COMP_DEBUG,
  12383. array("DEBUG"=>implode("\n",StripHTML($a_debug)))));
  12384. }
  12385. //
  12386. // Perform the computations in FMCalc
  12387. //
  12388. function Compute(&$a_field_order,&$a_cleaned_values,&$a_raw_data_values,
  12389. &$a_values)
  12390. {
  12391. global $FMCalc,$FM_UserErrors;
  12392. $a_mesgs = array();
  12393. $FM_UserErrors = array();
  12394. if (($a_flds = $FMCalc->Execute($a_mesgs)) !== false)
  12395. {
  12396. SendComputeAlerts();
  12397. foreach ($a_flds as $s_name=>$s_value)
  12398. {
  12399. $a_values[$s_name] = $s_value;
  12400. ProcessField($s_name,$s_value,$a_field_order,
  12401. $a_cleaned_values,$a_raw_data_values);
  12402. }
  12403. if (count($FM_UserErrors) > 0)
  12404. UserError("fmcompute_usererrors",GetMessage(MSG_USER_ERRORS),
  12405. "",$FM_UserErrors);
  12406. }
  12407. else
  12408. {
  12409. SendComputeAlerts();
  12410. Error("fmcompute_exec",GetMessage(MSG_COMP_EXEC,
  12411. array("ERRORS"=>implode("\n",$a_mesgs))),false,false);