· 11 years ago · Jun 26, 2015, 04:03 AM
1<?php
2$FM_VERS = "7.11"; // script version
3
4/* ex:set ts=4 sw=4:
5 * FormMail PHP script. This script requires PHP 4 or later.
6 * Copyright (c) 2001-2006 Root Software and Open Concepts Pty Ltd.
7 * All rights reserved.
8 *
9 * Visit us at http://www.tectite.com/
10 * for updates and more information.
11 *
12 **** If you use this 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 * Last Modified: RR 17:55 Mon 25 September 2006
18 * QVCS Version: $Revision: 1.109 $
19 *
20 * Read This First
21 * ~~~~~~~~~~~~~~~
22 * This script is very heavily documented! It looks daunting, but
23 * really isn't.
24 * If you have experience with PHP or other scripting languages,
25 * here's what you *need* to read:
26 * - Features
27 * - Configuration (TARGET_EMAIL & DEF_ALERT)
28 * - Creating Forms
29 * That's it! (Alternatively, just read the Quick Start section below).
30 *
31 * Quick Start
32 * ~~~~~~~~~~~
33 * 1. Edit this file and set TARGET_EMAIL for your requirements (approx
34 * line 2958 in this file - replace "yourhost\.com" with your mail server's
35 * name). We also strongly recommend you set DEF_ALERT (the next
36 * configuration below TARGET_EMAIL).
37 * 2. Install this file as formmail.php on your web server
38 * 3. Create an HTML form and:
39 * - specify a hidden field called "recipients" with the email address
40 * of the person to receive the form's results.
41 * - specify method "post" (or "get") and an action set to
42 * the formmail.php you uploaded to your web server
43 *
44 * Once you have FormMail working, you may be interested in some advanced
45 * usage and features. We have HOW-TO guides at www.tectite.com which
46 * describe many of the advanced processing you can do with FormMail.
47 *
48 * Purpose:
49 * ~~~~~~~~
50 * To accept HTTP POST information from a form and mail it to recipients.
51 * This version can also supply data to a TectiteCRM document, usually
52 * for insertion into the CRM database.
53 *
54 * What does this PHP script do?
55 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
56 * On your web site, you may have one or more HTML forms that accept
57 * information from people visiting your website. Your aim is for your
58 * website to email that information to you and/or add it to a database.
59 * formmail.php performs those functions.
60 *
61 * Features
62 * ~~~~~~~~
63 * - Optionally sends email of form results to recipients that
64 * can be specified in the form itself.
65 * - Optionally stores the form results in a CSV (comma-separated-
66 * values) file on your server.
67 * - Optionally logs form activity.
68 * - Optionally sends form results to a TectiteCRM document; generally,
69 * to automatically update the CRM database.
70 * - Recipient email addresses can be mangled in your forms to
71 * protect them from spambots.
72 * - Emails can be processed through any program (typically an
73 * encryption program) before sending.
74 * - Successful processing can redirect the user to any URL.
75 * For example, for downloads, we redirect the user to the file
76 * they want to download.
77 * - Supports any number of recipients. For security, recipient
78 * domains must be specified inside the script (see "Configuration"
79 * for details).
80 * - Failed processing can redirect to a custom URL.
81 * - Failed processing can be reported to a specific email address.
82 * - Supports both GET and POST methods of form submission.
83 * - Supports file uploads (multiple files can be uploaded).
84 * - Supports checkboxes and multiple-selection lists.
85 * - Supports CC and BCC addresses.
86 * - Supports deriving fields by concatenating other fields.
87 * - Supports exclusion of fields (in email)
88 * - Supports HTML emails via a template feature.
89 * - Supports complex field validation mechanisms.
90 * - Supports advanced user error handling features (including using our
91 * free fmbadhandler.php script).
92 * - Supports error and success template display.
93 * - Provides most of the features of other formmail scripts.
94 *
95 * Security
96 * ~~~~~~~~
97 * Security is the primary concern in accepting data from your website visitors.
98 * formmail.php has several security features designed into it. Note, however,
99 * it requires configuration for your particular web site.
100 *
101 * Configuration
102 * ~~~~~~~~~~~~~
103 * For instructions on configuring this program, go to the section
104 * titled "CONFIGURATION" (after reading the legal stuff below).
105 * There is only one mandatory setting: TARGET_EMAIL
106 *
107 * Creating Forms
108 * ~~~~~~~~~~~~~~
109 * This section explains how to call formmail.php from your HTML
110 * forms. You already need to know how to create an HTML form, but
111 * this section will tell you how to link it with this formmail script.
112 *
113 * Your form communicates its requirements to formmail.php through
114 * a set of "hidden" fields (using <INPUT TYPE="HIDDEN"...>). The data to
115 * be processed by formmail (e.g. the actual email to send) comes from
116 * a combination of hidden fields and other form fields (i.e. data entry
117 * fields from the user).
118 *
119 * Here are the steps to use formmail.php with your HTML form:
120 * 1. Create your HTML form using standard HTML
121 * 2. Ensure your form has the following fields defined. These are
122 * fields you expect the user to fill in:
123 * email the user's email address
124 * realname the real name of the user
125 * 3. Add the following hidden fields to your form. Note that all
126 * are optional:
127 * recipients a comma-separated list of email addresses that
128 * the form results will be sent to. These must
129 * be valid according to the "TARGET_EMAIL" configuration.
130 * Example:
131 * russ.robbo@rootsoftware.com,sales@rootsoftware.com.au
132 * alert_to email address to send errors/alerts to
133 * Example:
134 * webmaster@rootsoftware.com
135 * required a list of fields the user must provide, together
136 * with a friendly name. The field list is separated
137 * by commas, and you append the friendly name to
138 * the field name with a ':'.
139 * Example:
140 * email:Your email address,realname:Your name,Country,Reason:The reason you're interested in our product
141 * Note that field names and friendly names must not
142 * contain any of these characters:
143 * :|^!=,
144 * Advanced usage allows you to do the following:
145 * field1:name1|field2:name2
146 * either field1 or field2 is required
147 * (both allowed, too)
148 * field1:name1^field2:name2
149 * either field1 or field2 is required
150 * (both not allowed)
151 * field1:name1=field2:name2
152 * field1's value must be the same as
153 * field2's value
154 * field1:name1!=field2:name2
155 * field1's value must be different from
156 * field2's value
157 * In all the above ":name" is optional for any field.
158 *
159 * conditions a list of complex conditions, all of which must
160 * evaluate to true. Conditions are a more powerful
161 * alternative to the "required" specification.
162 * The list of conditions is separated by a character
163 * you specify by the first character in the list. You
164 * specify the internal conditions component separator
165 * as the second character in the list, as follows:
166 * name="conditions" value=":@condition1:condition2
167 * :condition3"
168 * specifies that the conditions are separated by the
169 * asterisk character.
170 * There are size limitations to fields, so you
171 * can specifie any number of conditions fields like
172 * this:
173 * name="conditions1" value=":@condition1:condition2
174 * :condition3"
175 * name="conditions2" value=":@condition4:condition5
176 * :condition6"
177 *
178 * A condition has this general format (spaces
179 * optional):
180 * COMMAND@ test1 @test2 @... @MESSAGE@
181 * COMMAND and MESSAGE are mandatory. MESSAGE is
182 * the message to display to the user if the condition
183 * fails.
184 * "@" is the internal separator that you specified
185 * as the second character of the conditions list.
186 * The tests are field comparisons, and have this
187 * general format:
188 * field1 OP field2
189 *
190 * OP is an operand. Tests are similar to the "required"
191 * specification, but the friendly field names are not
192 * allowed because you can provide a general message.
193 *
194 * field1
195 * field1 must have a value
196 * field1&field2
197 * both field1 and field2 must have a value
198 * field1|field2
199 * either field1 or field2 must have a value
200 * (both allowed, too)
201 * field1^field2
202 * either field1 or field2 must have a value
203 * (both not allowed)
204 * field1=field2
205 * field1's value must be the same as
206 * field2's value
207 * field1!=field2
208 * field1's value must be different from
209 * field2's value
210 * field1~pattern
211 * field1's value must match the specified
212 * perl regular expression
213 * field1!~pattern
214 * field1's value must not match the specified
215 * perl regular expression
216 * field1#=number
217 * field1's value is interpreted as a number
218 * and must equal the given number
219 * field1#!=number
220 * field1's value is interpreted as a number
221 * and must be not equal to the given number
222 * field1#<number
223 * field1's value is interpreted as a number
224 * and must be less than the given number
225 * field1#>number
226 * field1's value is interpreted as a number
227 * and must be greater than the given number
228 * field1#<=number
229 * field1's value is interpreted as a number
230 * and must be less than or equal to the given number
231 * field1#>=number
232 * field1's value is interpreted as a number
233 * and must be greater than or equal to the given number
234 * !
235 * the test evaluates to "false".
236 * an empty test evaluates to "true".
237 *
238 * The conditions are:
239 * @TEST@test@message@
240 * the test must be true. If not, the
241 * given message is shown.
242 * Example:
243 * @TEST@realname@Please provide your name so
244 * that we can address you properly.@
245 * This is exactly the same as a "required"
246 * specification except that you can provide
247 * an arbitrary message.
248 *
249 * @IF@test1@test2@test3@message@
250 * if test1 is true then test2
251 * must be true. If test1 is false then
252 * test3 must be true.
253 * Examples:
254 * @IF@salutation~/usefirst/@firstname@lastname@You
255 * must provide your first name if you
256 * want us to use it to address you or
257 * your last name for Mr., Mrs., etc.@
258 * says that firstname is required
259 * if salutation has the value "usefirst",
260 * and lastname is required otherwise.
261 * On failure, the given message is shown.
262 *
263 * @IF@payment~/ccard/@creditcard~/[1-9][0-9]{12,15}/@@You must
264 * enter your credit card number to
265 * pay by credit card.@
266 * says that if the payment value is "ccard"
267 * then the creditcard field must contain
268 * at least one digit.
269 *
270 * mail_options a list of options to control FormMail when
271 * sending email
272 * derive_fields a mechanism for deriving form fields by
273 * concatenating other form fields
274 * Example:
275 * realname=firstname+lastname,fullphone=area.phone,address=street*suburb
276 * Operators are:
277 * + concatenate with a single space between,
278 * but skip the space if the next field is
279 * empty
280 * . concatenate with no space between
281 * * concatenate with a single space between
282 * file_names a mechanism for naming the files uploaded by the
283 * form. By default the files will be named with
284 * user's original file name. This feature allows you
285 * to provide different names.
286 * The same features are available as for derive_fields.
287 * Example:
288 * file1=order_id.%'-1'%,file2=order_id.%'-2'%
289 * good_url the URL to redirect to on successful processing
290 * bad_url the URL to redirect to on failed processing
291 * this_form the URL of the form that's submitting the data;
292 * used with intelligent bad_url processing
293 * good_template a template file that FormMail can display on
294 * successful processing
295 * bad_template a template file that FormMail can display on
296 * failed processing
297 * template_list_sep a string to use when expanding lists
298 * of values in templates. The default is comma.
299 * subject a subject line for the email that's sent to your
300 * recipients
301 * Example:
302 * Form Submission
303 * env_report a comma-separated list of environment variables
304 * you want included in the email
305 * Example:
306 * REMOTE_HOST,REMOTE_ADDR,HTTP_USER_AGENT,AUTH_TYPE,REMOTE_USER
307 * filter name of a filter to process the email before sending.
308 * You can encode or encrypt the email, for example.
309 * filter_options comma-separated list of options to control the filter.
310 * filter_fields comma-separated list of fields to filter.
311 * The behaviour of this specification can vary slightly
312 * depending on your other specifications. Refer
313 * to our How-To guide on Filtering for more information.
314 * logfile name of a file to append activity to. Note that
315 * you must configure "LOGDIR" for this to work.
316 * Example:
317 * formmail.log
318 * csvfile name of the CSV database to append results to. Note that
319 * you must configure "CSVDIR" for this to work. You
320 * must also specify the csvcolumns field.
321 * Example:
322 * formmail.csv
323 * csvcolumns comma-separated list of field names you want to
324 * store in the CSV database. These are the field
325 * names in your form, and the order specifies the
326 * order for storage in the CSV database.
327 * Example:
328 * email,realname,Country,Reason
329 * autorespond comma-spearated list of specifications for the
330 * Auto Repsonder feature. Specifications are:
331 * Subject set to the subject line you
332 * want in the email sent to the user
333 * HTMLTemplate set to the name of the template
334 * to use for sending HTML email to
335 * the user
336 * PlainTemplate set to the name of the template
337 * to use for sending plain text email
338 * to the user
339 * TemplateMissing set to the string to use to
340 * fill in unsubmitted fields in template
341 * You can specify either HTMLTemplate or PlainTemplate
342 * or both.
343 * Example:
344 * Subject=Thanks for your purchase,HTMLTemplate=orderemail.htm
345 * crm_url a URL to send the form data to. This is for use
346 * with the TectiteCRM system.
347 * crm_spec a specification to pass to TectiteCRM. Please
348 * read the TectiteCRM documentation for details of
349 * how to use this field.
350 * crm_options options to control processing of TectiteCRM
351 * interface
352 *
353 * 4. Check that you've provided at least one of these fields:
354 * recipients, or
355 * logfile, or
356 * csvfile and csvcolumns, or
357 * crm_url and crm_spec
358 * If you don't specify any of these, then formmail.php will fail
359 * because you've given it no work to do!
360 *
361 * Note that we've provided a sample HTML form to get you started.
362 * Look for "Sample HTML Form Using FormMail" on our forums at
363 * http://www.tectite.com/.
364 *
365 * Note also that the default success and failure pages shown by formmail.php
366 * are quite basic. We recommend that you provide your own pages
367 * with "good_url" and "bad_url".
368 *
369 * Copying and Use
370 * ~~~~~~~~~~~~~~~
371 * formmail.php is provided free of charge and may be freely distributed
372 * and used provided that you:
373 * 1. keep this header, including copyright and comments,
374 * in place and unmodified; and,
375 * 2. do not charge a fee for distributing it, without an agreement
376 * in writing with Root Software allowing you to do so; and,
377 * 3. if you modify formmail.php before distributing it, you clearly
378 * identify:
379 * a) who you are
380 * b) how to contact you
381 * c) what changes you have made
382 * d) why you have made those changes.
383 *
384 * Warranty and Disclaimer
385 * ~~~~~~~~~~~~~~~~~~~~~~~
386 * formmail.php is provided free-of-charge and with ABSOLUTELY NO WARRANTY.
387 * It has not been verified for use in critical applications, including,
388 * but not limited to, medicine, defense, aircraft, space exploration,
389 * or any other potentially dangerous activity.
390 *
391 * By using formmail.php you agree to indemnify Root Software and
392 * Open Concepts Pty Ltd, their agents, employees, directors and
393 * associated companies and businesses from any liability whatsoever.
394 *
395 * We still care
396 * ~~~~~~~~~~~~~
397 * If you find a bug or fault in FormMail, please report it to us.
398 * We will respond to your report and make endeavours to rectify any
399 * faults you've detected as soon as possible.
400 * To contact us, visit http://www.tectite.com/contacts.php.
401 *
402 * Version History
403 * ~~~~~~~~~~~~~~~
404 *
405 **Version 7.11: 25-Sep-2006
406 *
407 * Fixed typographical error in defining the FILE_MODE constant. This typo appears
408 * to be harmless as PHP handled it automatically.
409 *
410 * Added new configuration option, SET_SENDER_FROM_EMAIL,
411 * to support yet another server requirement for sending email.
412 *
413 * Added extensive description of the email logic since different and
414 * conflicting server requirements are making it very difficult to
415 * understand.
416 *
417 * Fixed bug in handling multiple email addresses in the INI file
418 * (specifically, a list of email addresses for a word in the
419 * [email_addresses] section of the INI file.
420 *
421 **Version 7.10: 07-July-2006
422 *
423 * Fixes a vulnerability involving file uploads to the server.
424 * To be vulnerable, you would need both of these statements
425 * to be true:
426 * 1. You are using version 7.06 thru 7.09 of FormMail.
427 * 2. You have set FILEUPLOADS to true in FormMail's configuration..
428 * 3. You have set $FILE_REPOSITORY in FormMail's configuration.
429 *
430 * If any of these statements are false, then you are not vulnerable.
431 *
432 * The exploit for the vulnerability (which we won't publish at this time)
433 * is complex and specific to each server. In most cases it will not succeed
434 * because the web server software cannot write to arbitrary files on
435 * the server.
436 *
437 * We detected this problem though our QA procedures, and we have received
438 * no reports of any exploits.
439 *
440 * Mitigating this vulnerability is the fact that the documentation for
441 * file uploading to the server was only published in mid-June 2006. Also,
442 * while there are a large number of users of the vulnerable versions,
443 * very few enable file uploads to the server.
444 *
445 **Version 7.09: 30-May-2006
446 *
447 * Fixes a bug in using FromAddr (mail_options) with AT_MANGLE on some servers
448 * (those that require SENDMAIL_F_OPTION and/or INI_SET_FROM).
449 * Prior to this version, the FromAddr was not un-mangled before setting
450 * it for the server.
451 *
452 **Version 7.08: 28-Feb-2006
453 *
454 * Alerts now show the IP address of the user. Fixed minor issue
455 * in last version with showing the 'this_form' in alerts.
456 *
457 * Fixed some code formatting that had gone wonky.
458 *
459 * Implemented a new special field called "file_names". This is
460 * similar in syntax to "derive_fields" and allows you to provide
461 * different names for uploaded files.
462 *
463 * Empty derivations are now ignored - previously an alert was generated.
464 *
465 **Version 7.07: 18-Feb-2006
466 *
467 * Fixes a minor problem with using a file field name in good_template
468 * when the file has been stored on the server.
469 *
470 * Alert messages now show the referring page or the 'this_form' field
471 * so you can identify which form generated the alert.
472 *
473 * Implemented a Hook System. This allows you to include a PHP file within
474 * FormMail at various points.
475 *
476 * Implemented an "if" function for use when deriving fields.
477 *
478 **Version 7.06: 14-Feb-2006
479 *
480 * Added support for a form INI file. This allows you to set special fields
481 * and provide secret email addresses outside of the HTML form.
482 *
483 * Fixed a problem with processing conditions in the specified order. This
484 * problem would occur if you specified conditions7, conditions2, conditions1
485 * in that order. Now they will be processed in the order specified by their
486 * numeric ID.
487 *
488 * Added support for uploading the files to the server instead of attaching
489 * them.
490 *
491 * Added support for imgverify special field. You can now prevent form
492 * submission unless this matches the CAPTCHA string from verifyimg.php.
493 *
494 * A missing image verification string in the session is now reported
495 * as a system error (for imgverify or arverify). It indicates a failure
496 * in the PHP session processing.
497 *
498 * Added more features for handling file uploads. A file field can now:
499 * - be tested in "conditions" and "required". For "required", the value
500 * of the file field is the name of the file uploaded from the user's
501 * computer. Similarly for "conditions" on string testing. For
502 * "conditions" performing numeric comparisons, the file field
503 * expands to the size of the uploaded file in bytes.
504 * - be used to derive other fields. The name of the file is expanded
505 * in the derivation.
506 * - be used in templates. The name of the file is expanded in the
507 * derivation.
508 * - the size of a file can now be used to derive a field:
509 * fieldname = %size(filefield)%
510 *
511 * Improved IsFieldEmpty function to handle array values. This is
512 * really for future accuracy, as it shouldn't affect any current
513 * processing.
514 *
515 **Version 7.05: 27-Oct-2005
516 *
517 * Added support for HTTP authentication when using FMBadHandler.
518 * FormMail now sends the name and password to FMBadHandler so that
519 * it can return to the form.
520 *
521 * Added support for HTTP authentication when using multi-page forms.
522 * This is only needed when returning to the first page, as all other
523 * pages are templates.
524 *
525 **Version 7.04: 26-Sep-2005
526 *
527 * Removed parentheses which previously surrounded message numbers.
528 * Added new optional "mnums=no" parameter when using "testlang=1"
529 *
530 * Fixed bug in matching "selected" and "checked" attributes when processing
531 * multi-page forms. This bug only occurred under rare circumstances.
532 * An example is:
533 * <option value="Unselected">
534 * In this case, previous versions of FormMail would incorrectly match
535 * "selected" in the string "Unselected". Similarly for "checked".
536 * (This bug was also fixed in version 1.10 of FMBadHandler).
537 *
538 **Version 7.03: 24-Sep-2005
539 *
540 * Previously, when using multi-page forms on an SSL (HTTPS) connection,
541 * the return link for error handling was formatted like:
542 * http://yourdomain:443/.../formmail.php
543 * This is technically valid, but was a nuisance, especially when
544 * trying to compare this with your $TARGET_URLS settings.
545 * Version 7.03 improves this so that the return link is more
546 * conventional when using an SSL connection:
547 * https://yourdomain/.../formmail.php
548 *
549 * Added Attack Detection. FormMail has always been invulnerable
550 * to the attacks it now detects, so Attack Detection is merely to prevent
551 * annoying alert messages being sent to you when FormMail is attacked
552 * without you having to switch off all alert messages.
553 *
554 * Added new configuration setting $bShowMesgNumbers which allows you
555 * to control whether message numbers are shown with messages. The default
556 * is now "off" - as requested by numerous customers.
557 *
558 **Version 7.02: 18-Sep-2005
559 *
560 * Fixed bug in Multi-page forms. Some internal values were not being
561 * set with the right form field values.
562 * This meant that CSV files, for example, didn't store any data from
563 * previous pages in the sequence.
564 *
565 * Fixed bug in Multi-page forms whereby later field values were
566 * overwritten by earlier ones. For example:
567 * Page 1: set field "abc" to 50
568 * Page 2: set field "abc" to 60
569 * Page 3: sees field "abc" as value 50
570 *
571 * Added support for "Forward Remembrance" with Multi-page forms. This
572 * means that if a user enters a value on page N, then goes back to previous
573 * pages and then moves forward back to page N, they value they entered
574 * is restored to the page. This feature requires the use of "multi_keep"
575 * to tell FormMail which fields are to be remember this way. The sample
576 * package called "multitest2.zip" (downloadable from our website) demonstrates
577 * this feature.
578 *
579 **Version 7.01: 20-May-2005
580 *
581 * Added new configuration setting CHECK_DAYS. The default is 30, so
582 * now version checks only happen every 30 days instead of every 3 days.
583 *
584 * Mods for old versions of PHP:
585 * - "include" is now prefixed with the @ error control operator
586 * - all "fgets" calls now have the length parameter
587 *
588 * For Safe Mode operation, chdir for filters now only happens if the
589 * directory is not the current directory. This means you can put the
590 * filter command in the same directory as formmail.php and there's a better
591 * chance it will work if PHP is in Safe Mode.
592 *
593 **Version 7.00: 18-Apr-2005
594 ******* MAJOR UPGRADE *******
595 *
596 * Fixed some typographical errors in comments. Improved some configuration
597 * section documentation.
598 * Added new configuration settings:
599 * SESSION_NAME name of the PHP session to use
600 * FMCOMPUTE name of the fmcompute.php file
601 * FMGEOIP name of the fmgeoip.php file
602 *
603 * Added processing of <fmusererror></fmusererror> tags in error templates
604 * (these were only processed by FMBadHandler until now).
605 *
606 * Added support for new <fmsyserror></fmsyserror> tags in error templates.
607 *
608 * Added multi-page form support, which adds these new configuration:
609 * settings:
610 * MULTIFORMDIR
611 * MULTIFORMURL
612 *
613 * Improved use of $SET_REAL_DOCUMENT_ROOT so $REAL_DOCUMENT_ROOT is
614 * set from it before it is used in the default "encode" setting.
615 *
616 **Version 6.02: 17-Mar-2005
617 *
618 * Added system error message to the alert that's sent when a check file
619 * cannot be created.
620 *
621 * Added the "null" filter.
622 *
623 * Added new configuration setting ZERO_IS_EMPTY.
624 *
625 * Renamed "fm_modules" to "fmmodules".
626 *
627 * Implemented "and" for "conditions" testing.
628 *
629 **Version 6.01: 11-Mar-2005
630 *
631 * EMAIL_NAME now includes '-', so you can use this to match email
632 * addresses like "jack-smith@somesite.com".
633 * The Upgrade Wizard will put in the new value and discard your
634 * previous setting.
635 *
636 * Added some more comments/examples for Windows Servers.
637 *
638 * Added new filter options "KeepInLine". If you use the Attach option,
639 * you can also specify KeepInLine. KeepInLine causes the filtered
640 * results to be kept in the body of the email as well as being attached
641 * according to the Attach option. KeepInLine is ignored if Attach is
642 * not specified.
643 *
644 **Version 6.00: 20-Feb-2005
645 ******* MAJOR UPGRADE *******
646 *
647 * Added support for new FMCompute module. This creates new special
648 * fields called "fmcompute" or "fmcompute1...N", and "fm_modules".
649 * Adds new configuration $MODULEDIR to hold the directory for
650 * modules.
651 * Added GeoIP module support via FMCompute. Adds new configuration
652 * $GEOIP_LIC to hold your MaxMind license code.
653 * Created IncludePath functions.
654 *
655 **Version 5.03: 31-Jan-2005
656 *
657 * Workaround a problem with empty file uploads on some
658 * servers and/or PHP versions.
659 *
660 **Version 5.02: 19-Jan-2005
661 *
662 * Fixed problems with upgrading and copying the $FROM_USER and
663 * $REAL_DOCUMENT_ROOT configurations. $REAL_DOCUMENT_ROOT has
664 * been replaced with a setting called "$SET_REAL_DOCUMENT_ROOT".
665 *
666 * Added support for Environment Variables and Server Variables
667 * to be accessed to create derived fields.
668 *
669 * Fixed bug in last version when processing FromAddr.
670 *
671 **Version 5.00rc1: 10-Dec-2004
672 ******* MAJOR UPGRADE FOR INTERNATIONALIZATION *******
673 *
674 * Added support for languages other than English.
675 *
676 * FromAddr is now processed with the AT_MANGLE feature...this means you
677 * can hide this mail_options setting from spam bots too.
678 *
679 * Altered some error messages. Socket filter errors are no longer shown
680 * to the user.
681 *
682 **Version 4.10: 9-Dec-2004
683 *
684 * Added default setting for $TEMPLATEURL - without it the Upgrade Wizard
685 * failed to upgrade properly.
686 * Fixed bug in filtering process. This bug would probably not manifest
687 * on Unix servers, but may do on Windows servers.
688 *
689 **Version 4.09: 8-Dec-2004
690 *
691 * Added new configuration options:
692 * SENDMAIL_F_OPTION, which supersedes the "SendMailFOption" specification
693 * in "mail_options" in forms
694 * INI_SEND_FROM which allows you to workaround bad PHP
695 * configurations on Windows servers
696 *
697 **Version 4.08: 29-Nov-2004
698 *
699 * More changes to set $REAL_DOCUMENT_ROOT correctly. This is now
700 * also an optional configuration setting.
701 *
702 **Version 4.07: 29-Nov-2004
703 *
704 * Fixed bugs with handling regular expressions in "conditions" on
705 * server configurations with magic_quotes_gpc set On.
706 * With magic_quotes_gpc set On, any backslashes in your regular
707 * expressions would be stripped, thereby changing the meaning of your
708 * regular expressions.
709 *
710 * Fixed bugs with handling slashes in data. Backslashes were being stripped
711 * twice on server configurations with magic_quotes_gpc set On.
712 *
713 * Also fixes problems with storing CSV data that contains innocuous
714 * slashes. With LIMITED_IMPORT set to true, backslashes were being
715 * unnecessarily stripped.
716 * With LIMITED_IMPORT set to false, backslashes in data could cause the CSV
717 * file to be unreadable by an intelligent importing program because they
718 * were not being backslashed. They are now backslased (escaped).
719 *
720 **Version 4.06: 26-Nov-2004
721 *
722 * Removed unused variable that would cause a warning message
723 * on some systems.
724 *
725 **Version 4.05: 23-Nov-2004
726 *
727 * Removed debugging code that could prevent correct setting of
728 * $REAL_DOCUMENT_ROOT.
729 * A failure to send an alert message with the "testalert" feature
730 * now displays an error message.
731 * Added support for sending mail using PEAR.
732 *
733 **Version 4.04: 20-Nov-2004
734 *
735 * Disables "magic_quotes_runtime" setting, which breaks just about everything.
736 *
737 **Version 4.03: 14-Nov-2004
738 *
739 * Added new mail_options setting "FromAddr".
740 * You can specify an empty value or any email address. If this option is
741 * used, the sender of form results will be set to the given address
742 * instead of the value of the "email" field. This feature is necessary
743 * for certain servers which don't let software specify an arbitrary
744 * sender address. Yahoo is one such hosting service.
745 *
746 **Version 4.02: 28-Oct-2004
747 *
748 * Improved to handle PHP sessions for browsers with cookies disabled.
749 * This is primarily useful with Error Handling (including with our
750 * FMBadHandler script).
751 *
752 **Version 4.01: 16-Oct-2004
753 *
754 * Improved setting of $REAL_DOCUMENT_ROOT. This means the standard
755 * filter setting for "encode" is more likely to work without change
756 * on any server.
757 *
758 * Improved "testalert" feature to include some server variables in the
759 * email.
760 *
761 **Version 4.00: 12-Oct-2004
762 ******* MAJOR UPGRADE *******
763 *
764 * This new version provides new features that will be useful to
765 * users of FormMailDecoder.
766 *
767 * Added support for "filter_fields" feature. Your forms can now
768 * select which fields are to be filtered (encoded). All other
769 * fields will be shown normally. The behaviour of this feature is
770 * reasonably logical if you're also using the PlainTemplate and HTMLTemplate
771 * features. However, if you are using them, we recommend that you
772 * also specify the Attach feature in "filter_options".
773 *
774 * Added support for "filter_options" feature. Allows you to control
775 * the way a filter operates. Currently, only the "Attach" feature is
776 * provided:
777 * Attach if specified, the output of the filter is attached
778 * to the email instead of being inside the body of the
779 * message. You must provide the name of the file.
780 * Some examples:
781 * Attach=ccard.fmencoded
782 * Attach=data.txt
783 *
784 * See the HOW-TO guide on filtering for more information about these
785 * new features (http://www.tectite.com/fmhowto/guides.php).
786 *
787 **Version 3.01: 22-Sep-2004
788 *
789 * Workaround a problem in Microsoft IIS with uploaded files.
790 *
791 **Version 3.00: 2-Sep-2004
792 ******* MAJOR UPGRADE *******
793 *
794 * Implemented the long-awaited Auto Responder feature! Requires
795 * version 1.01 of "verifyimg.php".
796 *
797 * Improved the "Exclude" mail_option so that "realname" and "email"
798 * special fields can be excluded from the body of the email.
799 *
800 * Added PlainTemplate mail_option feature. You can now create a template
801 * that will be used for sending you a plain text email. You can use this,
802 * for example, to put the data into CSV format.
803 *
804 **Version 2.17: 31-Aug-2004
805 *
806 * When filling templates, values are now converted so that HTML
807 * special characters in the values cannot break the HTML output.
808 *
809 * Alert messages now include the subject from the Form. Thanks
810 * to Doug Wright for suggesting this.
811 *
812 * Added new "template_list_sep" hidden field. If you have list-type
813 * fields in your form (checkboxes, multi-selection list boxes) and these
814 * are expanded in a template, then FormMail uses "," to separate the values
815 * by default. You can specify a different separator with the
816 * template_list_sep hidden field. For example,
817 * <input type="hidden" name="template_list_sep" value="<br />" />
818 * will give you line breaks instead of comma.
819 *
820 * Added new mail_options setting "CharSet". Your form can specify the
821 * character set to be used in emails with this option. For example,
822 * <input type="hidden" name="mail_options" value="CharSet=utf-8" />
823 * Thanks to Wojtek Linde for requesting this feature.
824 * The default remains ISO-8859-1.
825 *
826 **Version 2.16: 18-Aug-2004
827 *
828 * Added new "good_template" hidden field. This defines the template
829 * to output (and fill) to the browser on successful submission.
830 *
831 * Added new "crm_options" hidden field to control processing
832 * of CRM submissions.
833 *
834 * Added support for templates from URLs. This means you can use a
835 * URL from $TEMPLATEURL instead of a file from $TEMPLATEDIR. This is great for
836 * dynamically generated web pages. This adds a new configuration variable
837 * called $TEMPLATEURL.
838 *
839 **Version 2.15: 4-Aug-2004
840 *
841 * Fixed a bug in testing the PHP version - a couple of lines
842 * were in the wrong order. This should stop "Undefined offset"
843 * error form appearing in your php_errors file.
844 *
845 * Fixed bug in handling HTML + text emails with file attachments.
846 * This bug was introduced after version 2.12.
847 *
848 * Improved MIME compliance with internal headers when BODY_LF is set
849 * to something other than "\r\n". Improved to use the HEAD_CRLF
850 * configuration variable.
851 *
852 **Version 2.14: 13-Jul-2004
853 *
854 * Fixed problem with using sslencode filter.
855 * Small redesign in the definition of filters for HTTP and HTTPs access so
856 * that the FormMail Upgrade Wizard can be used to upgrade FormMail
857 * to contain these new features.
858 *
859 **Version 2.13: 12-Jul-2004
860 *
861 * Added support for executing filters via HTTP and HTTPS connections.
862 * This overcomes the problem on some servers where even CGI-BIN programs
863 * cannot be executed through PHP's "popen" or "system" functions.
864 *
865 **Version 2.12: 25-Jun-2004
866 *
867 * Fixed bug in passing array variables to the bad_url via the session.
868 *
869 * Added new "SendMailFOption" option for "mail_options". This causes
870 * FormMail to provide the "-faddr" option when it calls the "mail" function.
871 * This is needed by certain sendmail server installations.
872 *
873 **Version 2.11: 23-Jun-2004
874 *
875 * Improved further so that if no email address is provided the From line
876 * is excluded (having a name only is not valid to RFC822).
877 * Fixed some typos in comments.
878 *
879 **Version 2.10: 21-Jun-2004
880 *
881 * Improved creation of email's From line - if neither the email
882 * or realname is provided, no From line is included in the email.
883 *
884 **Version 2.09: 29-May-2004
885 *
886 * Fixed bug: mail_options Exclude feature wouldn't allow a single field
887 * name.
888 *
889 * Derived fields can now include arbitrary literal character using
890 * this ASCII hexadecimal notation: %HH% where HH is two hexadecimal
891 * characters: for example, 27 is a single quote, 2B is +, 2E is ., etc.
892 *
893 * Added simple check for internet spiders....no alert is sent.
894 *
895 * Added CONFIG_CHECK feature - currently checks for security
896 * issues in TARGET_EMAIL patterns.
897 *
898 * Improved to destroy session data when no longer needed.
899 *
900 **Version 2.08: 23-May-2004
901 *
902 * Fixed bug: wasn't handling 'ampm' in derived fields expansions.
903 *
904 * Added support for version check on servers that don't provide SERVER_NAME
905 * (now uses a unique ID derived from $TARGET_EMAIL[0] instead of SERVER_NAME).
906 *
907 * Added optional SCRATCH_PAD configuration so that you can specify the
908 * a directory that FormMail can write to on your server.
909 *
910 * Temporary files are now created in SCRATCH_PAD if it's configured.
911 *
912 * Alert messages are now filtered if a filter is specified (this is for
913 * security purposes on the assumption that the filter is an encryption
914 * program).
915 *
916 * Alert messages now use BODY_LF everywhere for line termination.
917 *
918 **Version 2.07: 13-May-2004
919 *
920 * Fixed incorrect documentation for $CSVOPEN feature introduced
921 * in v2.06.
922 *
923 * Added $CSVLINE configuration. Use this to customize your line
924 * terminations in CSV files
925 *
926 **Version 2.06: 12-May-2004
927 *
928 * Added $CSVOPEN configuration. Use this to ensure a text file
929 * format for your operating system.
930 *
931 **Version 2.05: 11-May-2004
932 *
933 * Added $CSVQUOTE configuration. This allows you to specify
934 * the character used for quoting fields in a CSV file. If you don't
935 * want quotes, you can set it to any empty string.
936 * Quotes within fields in a CSV file are now swapped to the opposite
937 * quote of that specified in $CSVQUOTE.
938 *
939 **Version 2.04: 10-May-2004
940 *
941 * Passes some more information to the bad_url. This information is
942 * used by fmbadhandler.php.
943 * Template expansions now treat empty fields as missing.
944 * Template expansions now put HTML BR tags where any new lines are found.
945 * Some alerts provide more specific information
946 * Added ALERT_ON_USER_ERROR configuration.
947 * Switched off DEBUG mode that was accidentally left on.
948 * The version check flag file now shows the server name.
949 * The version check now works even if SERVER_NAME is not available.
950 *
951 **Version 2.03: 3-May-2004
952 *
953 * Internal release - not generally available.
954 *
955 **Version 2.02: 1-May-2004
956 *
957 * Fixed a problem that caused empty conditions to generate an alert message.
958 * Since empty conditions are the default, that's an annoying problem!
959 * Changed "Revision" to "Version" in this Version History.
960 *
961 **Version 2.01: 1-May-2004
962 *
963 * Added support for creating date and time fields automatically.
964 * Fixed some line formatting.
965 *
966 **Version 2.00: 1-May-2004
967 ******* MAJOR UPGRADE *******
968 *
969 * Several sections re-written to improve consistency and logic checking.
970 *
971 * Default FILTERS now includes "fmencoder".
972 *
973 * Added support for "cc" and "bcc" addresses. This only have an
974 * effect if "recipients" have also been specified.
975 *
976 * Added support for form checkboxes and multiple-selection lists
977 * (thanks to Ted Boardman for getting us started on that).
978 *
979 * Added a lot more checking and reporting of errors or problems.
980 *
981 * Added a special test parameter to confirm that the DEF_ALERT setting
982 * is working. The DEF_ALERT address is no longer subject to
983 * verification through TARGET_EMAIL. You can now specify any address
984 * for DEF_ALERT. ("alert_to" from a form is still tested against
985 * TARGET_EMAIL).
986 *
987 * Added support for file uploads. Note, the form must specify:
988 * enctype="multipart/form-data" method="post"
989 * (this is a requirement of file uploading, not FormMail).
990 *
991 * Added support for "mail_options" field. This provides
992 * extra control from the form. Options supported:
993 * NoEmpty FormMail won't send results for fields that are empty.
994 * KeepLines fields which contain lines (e.g. TEXTAREA's) keep the
995 * lines; without this option (i.e. the default) FormMail
996 * joins the lines together
997 * AlwaysList don't format as an email even if there's only one
998 * non-special field. If this option is set, the email is
999 * always formatted like this:
1000 * name1: value1
1001 * name2: value2
1002 * DupHeader duplicate some header lines in the body of the email;
1003 * this was the default prior to Version 2.00. If you've
1004 * upgraded from 1.XX and you want your emails to look the
1005 * same, include this option.
1006 * StartLine include a --START-- line before the fields. This
1007 * option only works if you also specify BodyHeader.
1008 * If you've upgraded from 1.XX and you want your emails to
1009 * look the same, include this option. The --START-- line
1010 * is useful for some filter programs.
1011 * Exclude a list of fields to exclude from the email (special
1012 * fields cannot be excluded)
1013 * HTMLTemplate name of a template file to use to create an HTML
1014 * formatted email
1015 * PlainTemplate name of a template file to use to create an plain text
1016 * email
1017 * TemplateMissing string to insert for fields that are empty,
1018 * when filling an email template (HTMLTemplate or PlainTemplate)
1019 * CharSet the character set to specify in the Content-Type for
1020 * emails. Default is ISO-8859-1.
1021 *
1022 * CSV file support now provides configurable separators (see
1023 * $CSVSEP, $CSVINTSEP, and $CSVQUOTE).
1024 *
1025 * Improved list processing so that list items can whitespace
1026 * around them (e.g. <input ... name="csvcolumns" value="col1, col2, col3">).
1027 *
1028 * Added support for derived fields.
1029 *
1030 * Errors are now distinguished between internal and user error. A user
1031 * error is, for example, failure to enter a field. Internal errors are
1032 * now shown as a generic message to the user (since the user can't do
1033 * anything about them).
1034 *
1035 * Generated pages are now XHTML compliant.
1036 *
1037 * Redirects now use several methods to perform the redirect:
1038 * Location header
1039 * JavaScript redirect
1040 * Text for the user: "please click here"
1041 *
1042 * All files that are opened are now subject to special processing to
1043 * prevent security breaches.
1044 *
1045 * All URLs that FormMail will open are now checked against the
1046 * TARGET_URLS setting (security feature).
1047 *
1048 * Added advanced tests in the "required" feature.
1049 *
1050 * Added complex field validations through the new "conditions" feature.
1051 *
1052 * Added new "bad_template" feature for customizing the error page.
1053 *
1054 * Improved "bad_url" handling - more error fields and data is now
1055 * send to "bad_url" so that it can redirect back to the original form.
1056 *
1057 * Added automatic regular check for new version of FormMail.
1058 *
1059 ******************************************************************************
1060 *
1061 **Version 1.22: 11-Feb-2004
1062 * Improved filter logic to handle options which might have slashes in them.
1063 * For example, a filter like "/path/to/fmencoder -k/path/to/keyfile.txt"
1064 * would not work (because the directory name was not evaluated correctly).
1065 * Added some more information when reporting filter failures.
1066 *
1067 **Version 1.21: 24-Jan-2004
1068 * Fixed bug: required fields were not being checked if the form
1069 * was not sending email (e.g. if it was just writing to a CSV file).
1070 * Added alert messages for failure to open CSV and LOG files.
1071 * Improved some documentation and added some TARGET_EMAIL example lines.
1072 *
1073 **Version 1.19 & 1.20: 19-Jan-2004
1074 * Added support for missing environment variables: if an environment variable
1075 * isn't in the environment, then FormMail looks in the server variables for it.
1076 *
1077 * Improved support for different server configurations; if SCRIPT_FILENAME
1078 * is not available, PATH_TRANSLATED is used; if one or more isn't available
1079 * no error message is produced (previous version displayed an error message
1080 * depending on the PHP configuration).
1081 *
1082 * Added configuration option for line termination in the email body.
1083 *
1084 * The FormMail version is now displayed in the default error page.
1085 *
1086 **Version 1.18: 13-Jan-2004
1087 * Fixed a problem when mail sending failed; now, FormMail reports the error
1088 * to the user (by going to bad_url or generating the standard error page)
1089 * instead of showing success.
1090 * Added support for GET method of form submission (FormMail automatically
1091 * detects the method from the PHP Server variables).
1092 *
1093 **Version 1.16 & 1.17: 4-Jan-2004 & 5-Jan-2004
1094 * Added support for PHP versions before 4.2.3 (i.e. from 4.0.0 onwards).
1095 *
1096 **Version 1.14 & 1.15: 3-Jan-2004
1097 * Added some more comments.
1098 *
1099 **Version 1.13: 29-Dec-2003
1100 * Added Quick Start section, some more samples, and some more comments.
1101 *
1102 **Version 1.12: 26-Sep-2003
1103 * Replaced use of PATH_TRANSLATED with the more reliable SCRIPT_FILENAME.
1104 *
1105 **Version 1.10 & 1.11: 16-Sep-2003
1106 * Added handling of magic_quotes_gpc setting.
1107 *
1108 **Version 1.9: 5-Sep-2003
1109 * Added ex/vi initialisation string.
1110 *
1111 **Version 1.8: 9-Jul-2003
1112 * Added a workaround for a PHP bug: http://bugs.php.net/bug.php?id=21311
1113 *
1114 **Version 1.7: 19-May-2003
1115 * If a form contains only one non-special field (a "special" field is
1116 * one of the pre-defined ones, like "email", "realname"), then formmail.php
1117 * formats the single field as the email to be sent. This feature allows
1118 * formmail.php to be used for a simple email interface.
1119 * Modified some wordings.
1120 *
1121 **Version 1.4: 13-May-2003
1122 * First released version.
1123 */
1124
1125 //
1126 // Capture the current date and time, for various purposes.
1127 //
1128$lNow = time();
1129
1130set_magic_quotes_runtime(0); // disable this silly setting (usually not enabled)
1131ini_set('track_errors',1); // enable $php_errormsg
1132
1133$aAlertInfo = array();
1134
1135$aPHPVERSION = array();
1136
1137$sLangID = ""; // the language ID
1138$aMessages = array(); // all FormMail messages in the appropriate
1139 // language
1140
1141 //
1142 // the following constants define all FormMail messages
1143 //
1144define('MSG_SCRIPT_VERSION',0); // This script requires at least PHP version...
1145define('MSG_END_VERS_CHK',1); // If you're happy...
1146define('MSG_VERS_CHK',2); // A later version of FormMail is available...
1147define('MSG_CHK_FILE_ERROR',3); // Unable to create check file...
1148define('MSG_UNK_VALUE_SPEC',4); // derive_fields: unknown value specification...
1149define('MSG_INV_VALUE_SPEC',5); // derive_fields: invalid value specification...
1150define('MSG_DERIVED_INVALID',6); // Some derive_fields specifications...
1151define('MSG_INT_FORM_ERROR',7); // Internal form error...
1152define('MSG_OPTIONS_INVALID',8); // Some mail_options settings...
1153define('MSG_PLSWAIT_REDIR',9); // Please wait while you are redirected...
1154define('MSG_IFNOT_REDIR',10); // If you are not redirected...
1155define('MSG_PEAR_OBJ',11); // Failed to create PEAR Mail object...
1156define('MSG_PEAR_ERROR',12); // PEAR Mail error...
1157define('MSG_NO_FOPT_ADDR',13); // You have specified "SendMailFOption"...
1158define('MSG_MORE_INFO',14); // More information...
1159define('MSG_INFO_STOPPED',15); // Extra alert information suppressed...
1160define('MSG_FM_ALERT',16); // FormMail alert
1161define('MSG_FM_ERROR',17); // FormMail script error
1162define('MSG_FM_ERROR_LINE',18); // The following error occurred...
1163define('MSG_USERDATA_STOPPED',19); // User data suppressed...
1164define('MSG_FILTERED',20); // This alert has been filtered...
1165define('MSG_TEMPLATES',21); // You must set either TEMPLATEDIR or TEMPLATEURL...
1166define('MSG_OPEN_TEMPLATE',22); // Failed to open template...
1167define('MSG_ERROR_PROC',23); // An error occurred while processing...
1168define('MSG_ALERT_DONE',24); // Our staff have been alerted...
1169define('MSG_PLS_CONTACT',25); // Please contact us directly...
1170define('MSG_APOLOGY',26); // We apologize for any inconvenience...
1171define('MSG_ABOUT_FORMMAIL',27); // Your form submission was processed by...
1172define('MSG_PREG_FAILED',28); // preg_match_all failed in FindCRMFields...
1173define('MSG_URL_INVALID',29); // CRM URL "$URL" is not valid...
1174define('MSG_URL_OPEN',30); // Failed to open Customer Relationship...
1175define('MSG_CRM_FAILED',31); // Failure report from CRM...
1176define('MSG_CRM_FORM_ERROR',32); // Your form submission was not...
1177define('MSG_OR',33); // "$ITEM1" or "$ITEM2"
1178define('MSG_NOT_BOTH',34); // not both "$ITEM1" and "$ITEM2"
1179define('MSG_XOR',35); // "$ITEM1" or "$ITEM2" (but not both)
1180define('MSG_IS_SAME_AS',36); // "$ITEM1" is the same as "$ITEM2"
1181define('MSG_IS_NOT_SAME_AS',37); // "$ITEM1" is not the same as "$ITEM2"
1182define('MSG_REQD_OPER',38); // Operator "$OPER" is not valid for "required"
1183define('MSG_PAT_FAILED',39); // Pattern operator "$OPER" failed: pattern...
1184define('MSG_COND_OPER',40); // Operator "$OPER" is not valid...
1185define('MSG_INV_COND',41); // Invalid "conditions" field...
1186define('MSG_COND_CHARS',42); // The conditions field "$FLD" is not valid...
1187define('MSG_COND_INVALID',43); // The conditions field "$FLD" is not valid...
1188define('MSG_COND_TEST_LONG',44); // Field "$FLD" has too many components...
1189define('MSG_COND_IF_SHORT',45); // Field "$FLD" has too few components for...
1190define('MSG_COND_IF_LONG',46); // Field "$FLD" has too many components for...
1191define('MSG_COND_UNK',47); // Field "$FLD" has an unknown command word...
1192define('MSG_MISSING',48); // Missing "$ITEM"...
1193define('MSG_NEED_ARRAY',49); // "$ITEM" must be an array...
1194define('MSG_SUBM_FAILED',50); // Your form submission has failed...
1195define('MSG_FILTER_WRONG',51); // Filter "$FILTER" is not properly...
1196define('MSG_FILTER_CONNECT',52); // Could not connect to site "$SITE"...
1197define('MSG_FILTER_PARAM',53); // Filter "$FILTER" has invalid parameter...
1198define('MSG_FILTER_OPEN_FILE',54); // Filter "$FILTER" cannot open file...
1199define('MSG_FILTER_FILE_ERROR',55); // Filter "$FILTER": read error on file...
1200define('MSG_FILTER_READ_ERROR',56); // Filter '$filter' failed: read error...
1201define('MSG_FILTER_NOT_OK',57); // Filter 'FILTER' failed...
1202define('MSG_FILTER_UNK',58); // Unknown filter...
1203define('MSG_FILTER_CHDIR',59); // Cannot chdir...
1204define('MSG_FILTER_NOTFOUND',60); // Cannot execute...
1205define('MSG_FILTER_ERROR',61); // Filter "$FILTER" failed...
1206define('MSG_FLD_NOTFOUND',62); // "$FIELD" is not a field submitted...
1207define('MSG_TEMPLATE_ERRORS',63); // Template "$NAME" caused the...
1208define('MSG_TEMPLATE_FAILED',64); // Failed to process template "$NAME"...
1209define('MSG_MIME_PREAMBLE',65); // (Your mail reader should not show this...
1210define('MSG_MIME_HTML',66); // This message has been generated by FormMail...
1211define('MSG_FILE_OPEN_ERROR',67); // Failed to open file "$NAME"...
1212define('MSG_ATTACH_DATA',68); // Internal error: AttachFile requires...
1213define('MSG_PHP_HTML_TEMPLATES',69); // HTMLTemplate option is only ...
1214define('MSG_PHP_FILE_UPLOADS',70); // For security reasons, file upload...
1215define('MSG_FILE_UPLOAD',71); // File upload attempt ignored...
1216define('MSG_FILE_UPLOAD_ATTACK',72);// Possible file upload attack...
1217define('MSG_PHP_PLAIN_TEMPLATES',73);// PlainTemplate option is only...
1218define('MSG_ATTACH_NAME',74); // filter_options: Attach must contain a name...
1219define('MSG_PHP_BCC',75); // Warning: BCC is probably not supported...
1220define('MSG_CSVCOLUMNS',76); // The "csvcolumns" setting is not...
1221define('MSG_CSVFILE',77); // The "csvfile" setting is not...
1222define('MSG_TARG_EMAIL_PAT_START',78); // Warning: Your TARGET_EMAIL pattern...
1223define('MSG_TARG_EMAIL_PAT_END',79); // Warning: Your TARGET_EMAIL pattern...
1224define('MSG_CONFIG_WARN',80); // The following potential problems...
1225define('MSG_PHP_AUTORESP',81); // Autorespond is only supported...
1226define('MSG_ALERT',82); // This is a test alert message...
1227define('MSG_NO_DEF_ALERT',83); // No DEF_ALERT value has been set....
1228define('MSG_TEST_SENT',84); // Test message sent. Check your email.....
1229define('MSG_TEST_FAILED',85); // FAILED to send alert message...
1230define('MSG_NO_DATA_PAGE',86); // This URL is a Form submission program...
1231define('MSG_REQD_ERROR',87); // The form required some values that you...
1232define('MSG_COND_ERROR',88); // Some of the values you provided...
1233define('MSG_CRM_FAILURE',89); // The form submission did not succeed...
1234define('MSG_FOPTION_WARN',90); // Warning: You've used SendMailFOption in...
1235define('MSG_NO_ACTIONS',91); // The form has an internal error...
1236define('MSG_NO_RECIP',92); // The form has an internal error...
1237define('MSG_INV_EMAIL',93); // Invalid email addresses...
1238define('MSG_FAILED_SEND',94); // Failed to send email...
1239define('MSG_ARESP_EMAIL',96); // No "email" field was found. Autorespond...
1240define('MSG_ARESP_SUBJ',97); // Your form submission...
1241define('MSG_LOG_NO_VERIMG',98); // No VerifyImgString in session...
1242define('MSG_ARESP_NO_AUTH',99); // Failed to obtain authorization...
1243define('MSG_LOG_NO_MATCH',100); // User did not match image...
1244define('MSG_ARESP_NO_MATCH',101); // Your entry did not match...
1245define('MSG_LOG_FAILED',102); // Failed
1246define('MSG_ARESP_FAILED',103); // Autoresponder failed
1247define('MSG_LOG_OK',104); // OK
1248define('MSG_THANKS_PAGE',105); // Thanks! We've received your....
1249define('MSG_LOAD_MODULE',106); // Cannot load module....
1250define('MSG_LOAD_FMCOMPUTE',107); // Cannot load FMCompute....
1251define('MSG_REGISTER_MODULE',108); // Cannot register module....
1252define('MSG_COMP_PARSE',109); // These parse errors occurred....
1253define('MSG_COMP_REG_DATA',110); // Failed to register data field....
1254define('MSG_COMP_ALERT',111); // The following alert messages....
1255define('MSG_COMP_DEBUG',112); // The following debug messages...
1256define('MSG_COMP_EXEC',113); // The following errors occurred....
1257define('MSG_REG_FMCOMPUTE',114); // Cannot register function...
1258define('MSG_USER_ERRORS',115); // A number of errors occurred...
1259define('MSG_CALL_PARAM_COUNT',116); // Invalid parameter count...
1260define('MSG_CALL_UNK_FUNC',117); // Unknown function...
1261define('MSG_SAVE_FILE',118); // Failed to save file....
1262define('MSG_CHMOD',119); // Failed to chmod file....
1263define('MSG_VERIFY_MISSING',120); // Image verification string missing...
1264define('MSG_VERIFY_MATCH',121); // Your entry did not match...
1265define('MSG_FILE_NAMES_INVALID',122);// Some file_names specifications...
1266define('MSG_FILE_NAMES_NOT_FILE',123);// Your file_names specification...
1267
1268define('MSG_AND',133); // "$ITEM1" and "$ITEM2"
1269define('MSG_NEXT_PLUS_GOOD',134); // The form specifies both next_form and....
1270define('MSG_MULTIFORM',135); // You must set either MULTIFORMDIR or MULTIFORMURL...
1271define('MSG_MULTIFORM_FAILED',136); // Failed to process multi-page form template "$NAME"...
1272define('MSG_NEED_THIS_FORM',137); // Multi-page forms require "this_form" field...
1273define('MSG_NO_PHP_SELF',138); // PHP on the server is not providing "PHP_SELF"
1274define('MSG_RETURN_URL_INVALID',139); // Return "$URL" is not valid...
1275define('MSG_GO_BACK',140); // Cannot 'go back' if not a multi-page form...
1276define('MSG_OPEN_URL',141); // Cannot open URL...
1277define('MSG_CANNOT_RETURN',142); // Cannot return to page....
1278define('MSG_ATTACK_DETECTED',143); // Server attack detected....
1279define('MSG_ATTACK_PAGE',144); // Your form submission....
1280define('MSG_ATTACK_MIME_INFO',145); // The field "$FLD" contained...
1281define('MSG_ATTACK_DUP_INFO',146); // The fields "$FLD1" and...
1282define('MSG_ATTACK_SPEC_INFO',147); // Special field "$FLD"...
1283
1284define('MSG_URL_PARSE',160); // URL parse failed
1285define('MSG_URL_SCHEME',161); // Unsupported URL scheme...
1286define('MSG_SOCKET',162); // Socket error ...
1287define('MSG_GETURL_OPEN',163); // Open URL failed: ...
1288
1289 //
1290 // The following are PHP's file upload error messages
1291 //
1292define('MSG_FILE_UPLOAD_ERR_UNK',180); // Unknown error code.
1293define('MSG_FILE_UPLOAD_ERR1',181); // The uploaded file exceeds the upload_max_filesize directive in php.ini.
1294define('MSG_FILE_UPLOAD_ERR2',182); // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.
1295define('MSG_FILE_UPLOAD_ERR3',183); // The uploaded file was only partially uploaded.
1296define('MSG_FILE_UPLOAD_ERR4',184); // No file was uploaded.
1297define('MSG_FILE_UPLOAD_SIZE',189); // Uploaded file "$NAME" is too big...
1298 // (not a PHP error code - internal maximum file size error)
1299
1300 //
1301 // following are for derive_fields functions
1302 //
1303define('MSG_DER_FUNC_ERROR',200); // derive_fields: invalid function....
1304define('MSG_DER_FUNC_SIZE_FMT',201); // function 'size' requires....
1305define('MSG_DER_FUNC_IF_FMT',202); // function 'if' requires....
1306
1307// <A NAME="MessageNumbers"> Jump to: <A HREF="#BuiltinMessages">
1308
1309 //
1310 // Return true if using the built-in language
1311 //
1312function IsBuiltInLanguage()
1313{
1314 global $sLangID;
1315
1316 return (strpos($sLangID,"builtin") !== false);
1317}
1318
1319$sSavePath = "";
1320$bPathSaved = false;
1321 //
1322 // Set include path to include the given directory.
1323 //
1324function AddIncludePath($s_dir = ".")
1325{
1326 global $sSavePath,$bPathSaved;
1327
1328 $s_path = ini_get('include_path');
1329 $i_path_len = strlen($s_path);
1330 $s_sep = IsServerWindows() ? ";" : ":"; // get path separator
1331 //
1332 // look for it in the include_path
1333 //
1334 $b_found = false;
1335 $i_pos = 0;
1336 $i_len = strlen($s_dir);
1337 while (!$b_found && ($i_pos = strpos($s_path,$s_dir,$i_pos)) !== false)
1338 {
1339 if ($i_pos == 0)
1340 {
1341 if ($i_len == $i_path_len)
1342 $b_found = true; // the path only has $s_dir
1343 elseif ($s_path{$i_len} == $s_sep)
1344 $b_found = true;
1345 }
1346 elseif ($s_path{$i_pos-1} == $s_sep &&
1347 ($i_pos + $i_len == $i_path_len ||
1348 $s_path{$i_pos + $i_len} == $s_sep))
1349 $b_found = true;
1350 if (!$b_found)
1351 $i_pos++;
1352 }
1353 if (!$b_found)
1354 {
1355 //
1356 // allow multiple calls, but only store the original path once
1357 //
1358 if (!$bPathSaved)
1359 $sSavePath = $s_path;
1360 if (empty($s_path))
1361 $s_path = $s_dir;
1362 else
1363 //
1364 // prepend the directory
1365 //
1366 $s_path = $s_dir.$s_sep.$s_path;
1367 ini_set('include_path',$s_path);
1368 $bPathSaved = true;
1369 }
1370}
1371
1372 //
1373 // Reset the include path after a call to AddIncludePath.
1374 //
1375function ResetIncludePath()
1376{
1377 global $sSavePath,$bPathSaved;
1378
1379 if ($bPathSaved)
1380 {
1381 ini_set('include_path',$sSavePath);
1382 $bPathSaved = false;
1383 }
1384}
1385
1386 //
1387 // Load a language file
1388 //
1389function LoadLanguageFile()
1390{
1391 global $aMessages,$sLangID;
1392
1393 AddIncludePath();
1394 @include("language.inc");
1395 ResetIncludePath();
1396}
1397
1398 //
1399 // Load the messages array from the default language, and then
1400 // override with an optional language file.
1401 // Note: all messages get the MNUM parameter sent which they can use.
1402 // If they don't use it, the message number is appended.
1403 //
1404function LoadBuiltinLanguage()
1405{
1406 global $aMessages,$sLangID;
1407
1408 $sLangID = "English (builtin)";
1409 // MSG_SCRIPT_VERSION is shown if the PHP version is too old to run
1410 // FormMail
1411 // Parameters:
1412 // $PHPREQ is the minimum required PHP version
1413 // $PHPVERS is the version the server currently has installed.
1414 $aMessages[MSG_SCRIPT_VERSION] = 'This script requires at least PHP version '.
1415 '$PHPREQ. You have PHP version $PHPVERS.';
1416
1417 // MSG_END_VERS_CHK is sent at the end of an Alert message when
1418 // FormMail detects that there's a newer version available
1419 // Parameters: none
1420 $aMessages[MSG_END_VERS_CHK] = '***************************************************\n'.
1421 'If you are happy with your current version and want\n'.
1422 'to stop these reminders, edit formmail.php and\n'.
1423 'set CHECK_FOR_NEW_VERSION to false.\n'.
1424 '***************************************************\n';
1425
1426 // MSG_VERS_CHK is sent in an Alert message when
1427 // FormMail detects that there's a newer version available
1428 // Parameters:
1429 // $TECTITE the website to go to
1430 // $FM_VERS the current FormMail version
1431 // $NEWVERS the new FormMail version that's available
1432 $aMessages[MSG_VERS_CHK] = 'A later version of FormMail is available from $TECTITE.\n'.
1433 'You are currently using version $FM_VERS.\n'.
1434 'The new version available is $NEWVERS.\n';
1435
1436 // MSG_CHK_FILE_ERROR is sent in an Alert message when
1437 // FormMail cannot create a file to record the time of version check.
1438 // Parameters:
1439 // $FILE the file name that could not be created
1440 // $ERROR the actual error message
1441 $aMessages[MSG_CHK_FILE_ERROR] = 'Unable to create check file "$FILE": $ERROR';
1442
1443 // MSG_UNK_VALUE_SPEC is sent in an Alert message when
1444 // a form uses an unknown value specification in derive_fields.
1445 // Parameters:
1446 // $SPEC the unknown value specification
1447 // $MSG additional message
1448 $aMessages[MSG_UNK_VALUE_SPEC] = 'derive_fields: unknown value specification '.
1449 '"$SPEC"$MSG';
1450
1451 // MSG_INV_VALUE_SPEC is sent in an Alert message when
1452 // a form uses a value specification in derive_fields that's
1453 // formatted incorrectly (missing terminating '%')
1454 // Parameters:
1455 // $SPEC the invalid value specification
1456 $aMessages[MSG_INV_VALUE_SPEC] = 'derive_fields: invalid value specification '.
1457 '"$SPEC" (possibly missing a "%")';
1458
1459 // MSG_DERIVED_INVALID is sent in an Alert message when
1460 // a form's derive_fields setting has errors
1461 // Parameters: none
1462 // A list of errors is appended on separate lines
1463 $aMessages[MSG_DERIVED_INVALID] = 'Some derive_fields specifications are invalid $MNUM:\n';
1464
1465 // MSG_INT_FORM_ERROR is sent in an Alert message and displayed
1466 // to the form user
1467 // Parameters: none
1468 $aMessages[MSG_INT_FORM_ERROR] = 'Internal form error';
1469
1470 // MSG_OPTIONS_INVALID is sent in an Alert message when
1471 // a form's options settings are invalid. This applies to
1472 // mail_options, filter_options, crm_options, and autorespond
1473 // Parameters:
1474 // $OPT the name of the options field
1475 // A list of errors is appended on separate lines
1476 $aMessages[MSG_OPTIONS_INVALID] = 'Some $OPT settings are undefined $MNUM:\n';
1477
1478 // MSG_PLSWAIT_REDIR is shown to the user for a redirect
1479 // with JavaScript
1480 // Parameters: none
1481 $aMessages[MSG_PLSWAIT_REDIR] = 'Please wait while you are redirected...';
1482
1483 // MSG_IFNOT_REDIR is shown to the user for a redirect
1484 // with JavaScript
1485 // Parameters:
1486 // $URL the URL to redirect to
1487 $aMessages[MSG_IFNOT_REDIR] = 'If you are not automatically redirected, '.
1488 'please <a href="$URL">click here</a>.';
1489
1490 // MSG_PEAR_OBJ is shown to the user if the PEAR Mail object
1491 // cannot be created
1492 // Parameters: none
1493 $aMessages[MSG_PEAR_OBJ] = 'Failed to create PEAR Mail object';
1494
1495 // MSG_PEAR_ERROR is sent in an Alert message if the PEAR Mail processing
1496 // reports an error
1497 // Parameters:
1498 // $MSG the error message from PEAR
1499 $aMessages[MSG_PEAR_ERROR] = 'PEAR Mail error: $MSG';
1500
1501 // MSG_NO_FOPT_ADDR is sent in an Alert message SendMailFOption is
1502 // specified in the form and no email address has been provided
1503 // Parameters: none
1504 $aMessages[MSG_NO_FOPT_ADDR] = 'You have specified "SendMailFOption" in your '.
1505 'form, but there is no email address to use';
1506
1507 // MSG_MORE_INFO is sent in an Alert message on a line by itself, just
1508 // before extra information about the FormMail processing that may have
1509 // led to the alert message
1510 // Parameters: none
1511 $aMessages[MSG_MORE_INFO] = 'More information:';
1512
1513 // MSG_INFO_STOPPED is sent in an Alert message to say that extra
1514 // alert information has been suppressed because of potential security
1515 // problems with showing it.
1516 // Parameters: none
1517 $aMessages[MSG_INFO_STOPPED] = '(Extra alert information suppressed for '.
1518 'security purposes. $MNUM)';
1519
1520 // MSG_FM_ALERT is sent as the subject line of an Alert message
1521 // Parameters: none
1522 $aMessages[MSG_FM_ALERT] = 'FormMail alert';
1523
1524 // MSG_FM_ERROR is sent as the subject line of an Alert message
1525 // Parameters: none
1526 $aMessages[MSG_FM_ERROR] = 'FormMail script error';
1527
1528 // MSG_FM_ERROR_LINE is sent in an Alert message on a
1529 // separate line to introduce the actual error message
1530 // Parameters: none
1531 $aMessages[MSG_FM_ERROR_LINE] = 'The following error occurred in FormMail $MNUM:';
1532
1533 // MSG_USERDATA_STOPPED is sent in an Alert message to say that the
1534 // user's data has been suppressed because of potential security
1535 // problems with showing it.
1536 // Parameters: none
1537 $aMessages[MSG_USERDATA_STOPPED] = '(User data suppressed for security '.
1538 'purposes. $MNUM)';
1539
1540 // MSG_FILTERED is sent in an Alert message to show what filter
1541 // has been used on the message
1542 // Parameters:
1543 // $FILTER the name of the filter
1544 $aMessages[MSG_FILTERED] = 'This alert has been filtered through "$FILTER" '.
1545 'for security purposes.';
1546
1547 // MSG_TEMPLATES is sent in an Alert message when a form tries
1548 // to use a template, but templates have not been configured in
1549 // formmail.php
1550 // Parameters: none
1551 $aMessages[MSG_TEMPLATES] = 'You must set either TEMPLATEDIR or TEMPLATEURL '.
1552 'in formmail.php before you can specify '.
1553 'templates in your forms.';
1554
1555 // MSG_OPEN_TEMPLATE is sent in an Alert message when FormMail cannot
1556 // open a template file
1557 // Parameters:
1558 // $NAME the name of the template file
1559 // $ERROR information about the error
1560 $aMessages[MSG_OPEN_TEMPLATE] = 'Failed to open template "$NAME" $MNUM: $ERROR';
1561
1562 // MSG_ERROR_PROC is shown to the user as part of an error
1563 // page. This message introduces the error.
1564 // Parameters: none
1565 $aMessages[MSG_ERROR_PROC] = 'An error occurred while processing the '.
1566 'form $MNUM.\n\n';
1567
1568 // MSG_ALERT_DONE is shown to the user as part of an error
1569 // page if an Alert message has been sent to the website owner.
1570 // Parameters: none
1571 $aMessages[MSG_ALERT_DONE] = 'Our staff have been alerted to the error $MNUM.\n';
1572
1573 // MSG_PLS_CONTACT is shown to the user as part of an error
1574 // page if an Alert message could *not* be sent to the website owner.
1575 // Parameters: none
1576 $aMessages[MSG_PLS_CONTACT] = 'Please contact us directly since this form '.
1577 'is not working $MNUM.\n';
1578
1579 // MSG_APOLOGY is shown to the user as part of an error
1580 // page as an apology for a problem with the form.
1581 // Parameters: none
1582 $aMessages[MSG_APOLOGY] = 'We apologize for any inconvenience this error '.
1583 'may have caused.';
1584
1585 // MSG_ABOUT_FORMMAIL is shown to the user at the foot of pages
1586 // generated by FormMail (e.g. the default "Thanks" page and default
1587 // error page).
1588 // Parameters:
1589 // $FM_VERS the FormMail version number
1590 // $TECTITE www.tectite.com
1591 $aMessages[MSG_ABOUT_FORMMAIL] = 'Your form submission was processed by '.
1592 '($FM_VERS), available from '.
1593 '<a href="http://$TECTITE/">$TECTITE</a>.';
1594
1595 // MSG_PREG_FAILED is sent in an Alert message if the TectiteCRM
1596 // system failed to return the expected result.
1597 // Parameters: none
1598 $aMessages[MSG_PREG_FAILED] = 'preg_match_all failed in FindCRMFields';
1599
1600 // MSG_URL_INVALID is sent in an Alert message if the specified
1601 // URL for TectiteCRM is not valid according to the TARGET_URLS
1602 // configuration setting
1603 // Parameters:
1604 // $URL the invalid URL
1605 $aMessages[MSG_URL_INVALID] = 'The URL "$URL" to access the Customer '.
1606 'Relationship Management System is not valid '.
1607 '(see TARGET_URLS in formmail.php)';
1608
1609 // MSG_URL_OPEN is sent in an Alert message if the specified
1610 // URL for TectiteCRM cannot be opened
1611 // Parameters:
1612 // $URL the invalid URL
1613 // $ERROR information about the error
1614 $aMessages[MSG_URL_OPEN] = 'Failed to open Customer Relationship '.
1615 'Management System URL "$URL" $MNUM: $ERROR';
1616
1617 // MSG_CRM_FAILED is sent in an Alert message if the TectiteCRM
1618 // system doesn't return an OK message
1619 // Parameters:
1620 // $URL the invalid URL
1621 // $MSG more information
1622 $aMessages[MSG_CRM_FAILED] = 'Failure report from Customer Relationship '.
1623 'Management System (url="$URL") $MNUM: $MSG';
1624
1625 // MSG_CRM_FORM_ERROR is shown to the user if the information
1626 // passed to TectiteCRM was not accepted
1627 // Parameters: none
1628 $aMessages[MSG_CRM_FORM_ERROR] = 'Your form submission was not accepted';
1629
1630 // MSG_AND is shown to the user; it shows two items separated
1631 // by "and"
1632 // Parameters:
1633 // $ITEM1 the first item
1634 // $ITEM2 the second item
1635 $aMessages[MSG_AND] = '"$ITEM1" and "$ITEM2"';
1636
1637 // MSG_OR is shown to the user; it shows two items separated
1638 // by "or"
1639 // Parameters:
1640 // $ITEM1 the first item
1641 // $ITEM2 the second item
1642 $aMessages[MSG_OR] = '"$ITEM1" or "$ITEM2"';
1643
1644 // MSG_NOT_BOTH is shown to the user; it shows two items that must
1645 // be specified together
1646 // Parameters:
1647 // $ITEM1 the first item
1648 // $ITEM2 the second item
1649 $aMessages[MSG_NOT_BOTH] = 'not both "$ITEM1" and "$ITEM2"';
1650
1651 // MSG_XOR is shown to the user; it shows two items that must
1652 // not be specified together
1653 // Parameters:
1654 // $ITEM1 the first item
1655 // $ITEM2 the second item
1656 $aMessages[MSG_XOR] = '"$ITEM1" or "$ITEM2" (but not both)';
1657
1658 // MSG_IS_SAME_AS is shown to the user; it shows two items that must
1659 // not be the same value
1660 // Parameters:
1661 // $ITEM1 the first item
1662 // $ITEM2 the second item
1663 $aMessages[MSG_IS_SAME_AS] = '"$ITEM1" is the same as "$ITEM2"';
1664
1665 // MSG_IS_NOT_SAME_AS is shown to the user; it shows two items that must
1666 // be the same value
1667 // Parameters:
1668 // $ITEM1 the first item
1669 // $ITEM2 the second item
1670 $aMessages[MSG_IS_NOT_SAME_AS] = '"$ITEM1" is not the same as "$ITEM2"';
1671
1672 // MSG_REQD_OPER is sent in an Alert message when an unknown
1673 // operator has been used in a "required" specification
1674 // Parameters:
1675 // $OPER the unknown operator
1676 $aMessages[MSG_REQD_OPER] = 'Operator "$OPER" is not valid for "required"';
1677
1678 // MSG_PAT_FAILED is sent in an Alert message when a "conditions" pattern
1679 // match has not matched anything (this isn't necessarily an error)
1680 // Parameters:
1681 // $OPER the "conditions" operator
1682 // $PAT the "conditions" pattern
1683 // $VALUE the value that was searched
1684 $aMessages[MSG_PAT_FAILED] = 'Pattern operator "$OPER" failed: pattern '.
1685 '"$PAT", value searched was "$VALUE".';
1686
1687 // MSG_COND_OPER is sent in an Alert message when a "conditions"
1688 // operator is not value
1689 // Parameters:
1690 // $OPER the "conditions" operator
1691 $aMessages[MSG_COND_OPER] = 'Operator "$OPER" is not valid for "conditions"';
1692
1693 // MSG_INV_COND is sent in an Alert message when a "conditions"
1694 // field is not valid
1695 // Parameters:
1696 // FLD the field name
1697 $aMessages[MSG_INV_COND] = 'Invalid "conditions" field "$FLD" - not a string or array.';
1698
1699 // MSG_COND_CHARS is sent in an Alert message when a "conditions"
1700 // field is missing the mandatory first 2 characters (the separators)
1701 // Parameters:
1702 // FLD the field name
1703 // COND the conditions field value
1704 $aMessages[MSG_COND_CHARS] = 'The conditions field "$FLD" is not valid. '.
1705 'You must provide the two separator '.
1706 'characters at the beginning. You had "$COND".';
1707
1708 // MSG_COND_INVALID is sent in an Alert message when a "conditions"
1709 // field has the wrong format
1710 // Parameters:
1711 // FLD the field name
1712 // COND the conditions field value
1713 // SEP the internal separator character for the field.
1714 $aMessages[MSG_COND_INVALID] = 'The conditions field "$FLD" is not valid. '.
1715 'There must be at least 5 components '.
1716 'separated by "$SEP". Your value was "$COND".';
1717
1718 // MSG_COND_TEST_LONG is sent in an Alert message when a "conditions"
1719 // TEST value has too many components
1720 // Parameters:
1721 // FLD the field name
1722 // COND the conditions field value
1723 // SEP the list separator character for the field.
1724 $aMessages[MSG_COND_TEST_LONG] = 'Field "$FLD" has too many components for '.
1725 'a "TEST" command: "$COND".\nAre you missing '.
1726 'a "$SEP"?';
1727
1728 // MSG_COND_IF_SHORT is sent in an Alert message when a "conditions"
1729 // IF value has too few components
1730 // Parameters:
1731 // FLD the field name
1732 // COND the conditions field value
1733 // SEP the internal separator character for the field.
1734 $aMessages[MSG_COND_IF_SHORT] = 'Field "$FLD" has too few components for '.
1735 'an "IF" command: "$COND".\nThere must be '.
1736 'at least 6 components separated by "$SEP"';
1737
1738 // MSG_COND_IF_LONG is sent in an Alert message when a "conditions"
1739 // IF value has too many components
1740 // Parameters:
1741 // FLD the field name
1742 // COND the conditions field value
1743 // SEP the list separator character for the field.
1744 $aMessages[MSG_COND_IF_LONG] = 'Field "$FLD" has too many components for '.
1745 'an "IF" command: "$COND".\nAre you missing '.
1746 'a "$SEP"?';
1747
1748 // MSG_COND_UNK is sent in an Alert message when a "conditions"
1749 // value has an unknown command
1750 // Parameters:
1751 // FLD the field name
1752 // COND the conditions field value
1753 // CMD the unknown command
1754 $aMessages[MSG_COND_UNK] = 'Field "$FLD" has an unknown command word '.
1755 '"$CMD": "$COND".';
1756
1757 // MSG_MISSING is sent in an Alert message when
1758 // a socket filter is incorrectly defined
1759 // Parameters:
1760 // ITEM the missing item
1761 $aMessages[MSG_MISSING] = 'Missing "$ITEM"';
1762
1763 // MSG_NEED_ARRAY is sent in an Alert message when
1764 // a socket filter is incorrectly defined
1765 // Parameters:
1766 // ITEM the item that should be an array
1767 $aMessages[MSG_NEED_ARRAY] = '"$ITEM" must be an array';
1768
1769 // MSG_SUBM_FAILED is shown to the user when an internal error
1770 // as occurred and that error is not to be shown
1771 // Parameters: none
1772 $aMessages[MSG_SUBM_FAILED] = 'Your form submission has failed due to '.
1773 'an error on our server.';
1774
1775 // MSG_FILTER_WRONG is sent in an Alert message when
1776 // a socket filter is incorrectly defined
1777 // Parameters:
1778 // FILTER the filter name
1779 // ERRORS a string containing a list of errors
1780 $aMessages[MSG_FILTER_WRONG] = 'Filter "$FILTER" is not properly defined: '.
1781 '$ERRORS';
1782
1783 // MSG_FILTER_CONNECT is sent in an Alert message when FormMail
1784 // cannot connect to a socket filter
1785 // Parameters:
1786 // FILTER the filter name
1787 // SITE the site
1788 // ERRNUM socket error number
1789 // ERRSTR socket error message
1790 $aMessages[MSG_FILTER_CONNECT] = 'Could not connect to site "$SITE" '.
1791 'for filter "$FILTER" ($ERRNUM): $ERRSTR';
1792
1793 // MSG_FILTER_PARAM is sent in an Alert message when a socket
1794 // filter has an invalid parameter specification
1795 // Parameters:
1796 // FILTER the filter name
1797 // NUM parameter number
1798 // NAME parameter name
1799 $aMessages[MSG_FILTER_PARAM] = 'Filter "$FILTER" has invalid parameter '.
1800 '#$NUM: no "$NAME"';
1801
1802 // MSG_FILTER_OPEN_FILE is sent in an Alert message when a socket
1803 // filter cannot open the required file
1804 // Parameters:
1805 // FILTER the filter name
1806 // FILE the file that could not be opened
1807 // ERROR the error message
1808 $aMessages[MSG_FILTER_OPEN_FILE] = 'Filter "$FILTER" cannot open file '.
1809 '"$FILE": $ERROR';
1810
1811 // MSG_FILTER_FILE_ERROR is sent in an Alert message when a socket
1812 // filter gets an error message during reading a file
1813 // Parameters:
1814 // FILTER the filter name
1815 // FILE the file that could not be opened
1816 // ERROR the error message
1817 // NLINES the number of lines that were read successfully
1818 $aMessages[MSG_FILTER_FILE_ERROR] = 'Filter "$FILTER": read error on file '.
1819 '"$FILE" after $NLINES lines: $ERROR';
1820
1821 // MSG_FILTER_READ_ERROR is sent in an Alert message when a socket
1822 // filter gets an error during reading from the socket
1823 // Parameters:
1824 // FILTER the filter name
1825 // ERROR the error message
1826 $aMessages[MSG_FILTER_READ_ERROR] = 'Filter "$FILTER" failed: read error: '.
1827 '$ERROR';
1828
1829 // MSG_FILTER_NOT_OK is sent in an Alert message when a socket
1830 // filter fails to return the agreed __OK__ indicator
1831 // Parameters:
1832 // FILTER the filter name
1833 // DATA the data returned from the filter
1834 $aMessages[MSG_FILTER_NOT_OK] = 'Filter "$FILTER" failed (missing '.
1835 '__OK__ line): $DATA';
1836
1837 // MSG_FILTER_UNK is sent in an Alert message
1838 // when an unknown filter is specified by a form
1839 // Parameters:
1840 // FILTER the filter name
1841 $aMessages[MSG_FILTER_UNK] = 'Unknown filter "$FILTER"';
1842
1843 // MSG_FILTER_CHDIR is sent in an Alert message
1844 // when FormMail cannot change to the filter's directory
1845 // Parameters:
1846 // FILTER the filter name
1847 // DIR the directory name
1848 // ERROR an error message from the system
1849 $aMessages[MSG_FILTER_CHDIR] = 'Cannot chdir to "$DIR" to run filter '.
1850 '"$FILTER": $ERROR';
1851
1852 // MSG_FILTER_NOTFOUND is sent in an Alert message
1853 // when FormMail cannot execute the filter
1854 // Parameters:
1855 // FILTER the filter name
1856 // CMD the command line being executed
1857 // ERROR an error message from the system
1858 $aMessages[MSG_FILTER_NOTFOUND] = 'Cannot execute filter "$FILTER" with '.
1859 'command "$CMD": $ERROR';
1860
1861 // MSG_FILTER_ERROR is sent in an Alert message
1862 // when a filter returns a non-zero status
1863 // Parameters:
1864 // FILTER the filter name
1865 // ERROR an error message from the system
1866 // STATUS the status return from the command
1867 $aMessages[MSG_FILTER_ERROR] = 'Filter "$FILTER" failed (status $STATUS): '.
1868 '$ERROR';
1869
1870 // MSG_FLD_NOTFOUND is sent as part of an Alert message
1871 // when a template refers to a non-existent form field
1872 // Parameters:
1873 // FIELD the field name
1874 $aMessages[MSG_FLD_NOTFOUND] = '"$FIELD" is not a field submitted from the form';
1875
1876 // MSG_TEMPLATE_ERRORS is sent as part of an Alert message
1877 // when a template has generated some errors. The message
1878 // should end with a new line and the actual errors are
1879 // output after it.
1880 // Parameters:
1881 // NAME the template name
1882 $aMessages[MSG_TEMPLATE_ERRORS] = 'Template "$NAME" caused the '.
1883 'following errors $MNUM:\n';
1884
1885 // MSG_TEMPLATE_FAILED is sent in an Alert message
1886 // when processing a template has failed.
1887 // Parameters:
1888 // NAME the template name
1889 $aMessages[MSG_TEMPLATE_FAILED] = 'Failed to process template "$NAME"';
1890
1891 // MSG_MIME_PREAMBLE is sent in the preamble of MIME emails
1892 // Parameters: none
1893 $aMessages[MSG_MIME_PREAMBLE] = '(Your mail reader should not show this '.
1894 'text.\nIf it does you may need to '.
1895 'upgrade to more modern software.)';
1896
1897 // MSG_MIME_HTML is sent in the preamble of HTML emails
1898 // Parameters:
1899 // NAME the template name
1900 $aMessages[MSG_MIME_HTML] = 'This message has been generated by FormMail '.
1901 'using an HTML template\ncalled "$NAME". The '.
1902 'raw text of the form results\nhas been '.
1903 'included below, but your mail reader should '.
1904 'display the HTML\nversion only (unless it\'s '.
1905 'not capable of doing so).';
1906
1907 // MSG_FILE_OPEN_ERROR is sent in an Alert message when FormMail
1908 // cannot open a file
1909 // Parameters:
1910 // NAME the file name
1911 // TYPE the type of file
1912 // ERROR the system error message
1913 $aMessages[MSG_FILE_OPEN_ERROR] = 'Failed to open $TYPE file "$NAME": $ERROR';
1914
1915 // MSG_ATTACH_DATA is sent in an Alert message when the file
1916 // attachment through 'data' has gone wrong.
1917 // Parameters: none
1918 $aMessages[MSG_ATTACH_DATA] = 'Internal error: AttachFile requires '.
1919 '"tmp_name" or "data"';
1920
1921 // MSG_PHP_HTML_TEMPLATES is sent in an Alert message when an
1922 // HTML template is used but the PHP version is too old.
1923 // Parameters:
1924 // $PHPVERS the current PHP version
1925 $aMessages[MSG_PHP_HTML_TEMPLATES] = 'HTMLTemplate option is only supported '.
1926 'with PHP version 4.0.5 or above. Your '.
1927 'server is running version $PHPVERS.';
1928
1929 // MSG_PHP_FILE_UPLOADS is sent in an Alert message when
1930 // file upload is used but the PHP version is too old.
1931 // Parameters:
1932 // $PHPVERS the current PHP version
1933 $aMessages[MSG_PHP_FILE_UPLOADS] = 'For security reasons, file upload is only '.
1934 'allowed with PHP version 4.0.3 or above. '.
1935 'Your server is running version $PHPVERS.';
1936
1937 // MSG_FILE_UPLOAD is sent in an Alert message when
1938 // file upload is attempted but FormMail is not configured to allow
1939 // it
1940 // Parameters: none
1941 $aMessages[MSG_FILE_UPLOAD] = 'File upload attempt ignored';
1942
1943 // MSG_FILE_UPLOAD_ATTACK is sent in an Alert message when
1944 // possible file upload attack is detected
1945 // Parameters:
1946 // NAME file name
1947 // TEMP temporary file name
1948 $aMessages[MSG_FILE_UPLOAD_ATTACK] = 'Possible file upload attack '.
1949 'detected: name="$NAME" temp name='.
1950 '"$TEMP"';
1951
1952 // MSG_PHP_PLAIN_TEMPLATES is sent in an Alert message when a
1953 // Plain template is used but the PHP version is too old.
1954 // Parameters:
1955 // $PHPVERS the current PHP version
1956 $aMessages[MSG_PHP_PLAIN_TEMPLATES] = 'PlainTemplate option is only supported '.
1957 'with PHP version 4.0.5 or above. Your '.
1958 'server is running version $PHPVERS.';
1959
1960 // MSG_ATTACH_NAME is sent in an Alert message when a
1961 // the form uses the Attach feature without specifying a file name
1962 // Parameters: none
1963 $aMessages[MSG_ATTACH_NAME] = 'filter_options: Attach must contain a name '.
1964 '(e.g. Attach=data.txt)';
1965
1966 // MSG_PHP_BCC is sent in an Alert message when a
1967 // the form uses the BCC feature and the PHP version may not support it
1968 // Parameters:
1969 // $PHPVERS the current PHP version
1970 $aMessages[MSG_PHP_BCC] = 'Warning: BCC is probably not supported on your '.
1971 'PHP version ($PHPVERS)';
1972
1973 // MSG_CSVCOLUMNS is sent in an Alert message when a csvcolumns field
1974 // is not correct
1975 // Parameters:
1976 // $VALUE the csvcolumns field value
1977 $aMessages[MSG_CSVCOLUMNS] = 'The "csvcolumns" setting is not '.
1978 'valid: "$VALUE"';
1979
1980 // MSG_CSVFILE is sent in an Alert message when a csvfile field
1981 // is not correct
1982 // Parameters:
1983 // $VALUE the csvfile field value
1984 $aMessages[MSG_CSVFILE] = 'The "csvfile" setting is not valid: "$VALUE"';
1985
1986 // MSG_TARG_EMAIL_PAT_START is sent in an Alert message when a
1987 // $TARGET_EMAIL pattern is insecure because of a missing '^'
1988 // at the beginning
1989 // Parameters:
1990 // $PAT the pattern
1991 $aMessages[MSG_TARG_EMAIL_PAT_START] = 'Warning: Your TARGET_EMAIL pattern '.
1992 '"$PAT" is missing a ^ at the '.
1993 'beginning.';
1994
1995 // MSG_TARG_EMAIL_PAT_END is sent in an Alert message when a
1996 // $TARGET_EMAIL pattern is insecure because of a missing '$'
1997 // at the end
1998 // Parameters:
1999 // $PAT the pattern
2000 $aMessages[MSG_TARG_EMAIL_PAT_END] = 'Warning: Your TARGET_EMAIL pattern '.
2001 '"$PAT" is missing a $ at the end.';
2002
2003 // MSG_CONFIG_WARN is sent in an Alert message when the FormMail
2004 // configuration may have some problems. The messages are
2005 // passed on separate lines, so the line terminations below
2006 // are important.
2007 // Parameters:
2008 // $MESGS lines of messages
2009 $aMessages[MSG_CONFIG_WARN] = 'The following potential problems were found '.
2010 'in your configuration:\n$MESGS\n\n'.
2011 'These are not necessarily errors, but you '.
2012 'should review the documentation\n'.
2013 'inside formmail.php. If you are sure your '.
2014 'configuration is correct\n'.
2015 'you can disable the above messages by '.
2016 'changing the CONFIG_CHECK settings.';
2017
2018 // MSG_PHP_AUTORESP is sent in an Alert message when the PHP version
2019 // does not support autoresponding
2020 // Parameters:
2021 // $PHPVERS current PHP version
2022 $aMessages[MSG_PHP_AUTORESP] = 'Autorespond is only supported with PHP '.
2023 'version 4.0.5 or above. Your server is '.
2024 'running version $PHPVERS.';
2025
2026 // MSG_ALERT is the test alert message (formmail.php?testalert=1)
2027 // Parameters:
2028 // $LANG the language ID
2029 // $PHPVERS PHP version
2030 // $FM_VERS FormMail version
2031 // $SERVER server type
2032 // $DOCUMENT_ROOT PHP's DOCUMENT_ROOT value
2033 // $SCRIPT_FILENAME PHP's SCRIPT_FILENAME value
2034 // $PATH_TRANSLATED PHP's PATH_TRANSLATED value
2035 // $REAL_DOCUMENT_ROOT the REAL_DOCUMENT_ROOT value
2036 $aMessages[MSG_ALERT] = 'This is a test alert message $MNUM\n'.
2037 'Loaded language is $LANG\n'.
2038 'PHP version is $PHPVERS\n'.
2039 'FormMail version is $FM_VERS\n'.
2040 'Server type: $SERVER\n'.
2041 '\n'.
2042 'DOCUMENT_ROOT: $DOCUMENT_ROOT\n'.
2043 'SCRIPT_FILENAME: $SCRIPT_FILENAME\n'.
2044 'PATH_TRANSLATED: $PATH_TRANSLATED\n'.
2045 'REAL_DOCUMENT_ROOT: $REAL_DOCUMENT_ROOT';
2046
2047 // MSG_NO_DEF_ALERT is displayed if you use the testalert feature
2048 // and no DEF_ALERT setting has been provided.
2049 // Parameters: none
2050 $aMessages[MSG_NO_DEF_ALERT] = 'No DEF_ALERT value has been set.';
2051
2052 // MSG_TEST_SENT is displayed if when use the testalert feature
2053 // Parameters: none
2054 $aMessages[MSG_TEST_SENT] = 'Test message sent. Check your email.';
2055
2056 // MSG_TEST_FAILED is displayed if when use the testalert feature
2057 // and the mail sending fails.
2058 // Parameters: none
2059 $aMessages[MSG_TEST_FAILED] = 'FAILED to send alert message. Check your '.
2060 'server error logs.';
2061
2062 // MSG_NO_DATA_PAGE is the page that's displayed if the user
2063 // just opens the URL to FormMail directly.
2064 // Parameters: none
2065 $aMessages[MSG_NO_DATA_PAGE] = 'This URL is a Form submission program.\n'.
2066 'It appears the form is not working '.
2067 'correctly as there was no data found.\n'.
2068 'You\'re not supposed to browse to this '.
2069 'URL; it should be accessed from a form.';
2070
2071 // MSG_REQD_ERROR is displayed to the user as a default error
2072 // message when they haven't supplied some required fields
2073 // Parameters: none
2074 $aMessages[MSG_REQD_ERROR] = 'The form required some values that you '.
2075 'did not seem to provide.';
2076
2077 // MSG_COND_ERROR is displayed to the user as a default error
2078 // message when some form conditions have failed
2079 // Parameters: none
2080 $aMessages[MSG_COND_ERROR] = 'Some of the values you provided are not valid.';
2081
2082 // MSG_CRM_FAILURE is displayed to the user when submission
2083 // to the CRM has failed.
2084 // Parameters: none
2085 $aMessages[MSG_CRM_FAILURE] = 'The form submission did not succeed due to '.
2086 'a CRM failure.';
2087
2088 // MSG_FOPTION_WARN is sent in an Alert message when the form
2089 // uses the superseded SendMailFOption feature
2090 // Parameters:
2091 // $LINE line number for SENDMAIL_F_OPTION
2092 $aMessages[MSG_FOPTION_WARN] = 'Warning: You\'ve used SendMailFOption in '.
2093 '"mail_options" in your form. This has been '.
2094 'superseded with a configuration setting '.
2095 'inside formmail.php. Please update your '.
2096 'formmail.php configuration (look for '.
2097 'SENDMAIL_F_OPTION on line $LINE) and set '.
2098 'it to "true", then remove SendMailFOption '.
2099 'from your form(s).';
2100
2101 // MSG_NO_ACTIONS is sent in an Alert message when there is no
2102 // action to perform or email address to send to
2103 // Parameters: none
2104 $aMessages[MSG_NO_ACTIONS] = 'The form has an internal error - no actions '.
2105 'or recipients were specified.';
2106
2107 // MSG_NO_RECIP is sent in an Alert message when there are no
2108 // valid recipients to send to
2109 // Parameters: none
2110 $aMessages[MSG_NO_RECIP] = 'The form has an internal error - no valid '.
2111 'recipients were specified.';
2112
2113 // MSG_INV_EMAIL is sent in an Alert message when there are errors
2114 // in the email addresses specified in the form
2115 // Parameters:
2116 // $ERRORS list of errors
2117 $aMessages[MSG_INV_EMAIL] = 'Invalid email addresses were specified '.
2118 'in the form $MNUM:\n$ERRORS';
2119
2120 // MSG_FAILED_SEND is sent in an Alert message when the mail sending fails.
2121 // Parameters: none
2122 $aMessages[MSG_FAILED_SEND] = 'Failed to send email';
2123
2124 // MSG_ARESP_EMAIL is sent in an Alert message when
2125 // no email address has been specified for an autoreponse
2126 // Parameters: none
2127 $aMessages[MSG_ARESP_EMAIL] = 'No "email" field was found. Autorespond '.
2128 'requires the submitter\'s email address.';
2129
2130 // MSG_ARESP_SUBJ is the default subject for the auto response email
2131 // Parameters: none
2132 $aMessages[MSG_ARESP_SUBJ] = 'Your form submission';
2133
2134 // MSG_LOG_NO_VERIMG is written to the auto respond log file
2135 // if no VerifyImgString session variable was found
2136 // Parameters: none
2137 $aMessages[MSG_LOG_NO_VERIMG] = 'No VerifyImgString in session';
2138
2139 // MSG_ARESP_NO_AUTH is shown to the user
2140 // if no VerifyImgString session variable was found
2141 // Parameters: none
2142 $aMessages[MSG_ARESP_NO_AUTH] = 'Failed to obtain authorization to send '.
2143 'you email. This is probably a fault on '.
2144 'the server.';
2145
2146 // MSG_LOG_NO_MATCH is written to the auto respond log file
2147 // if the user's entry did not match the image verification
2148 // Parameters: none
2149 $aMessages[MSG_LOG_NO_MATCH] = 'User did not match image';
2150
2151 // MSG_ARESP_NO_MATCH is shown to the user
2152 // if the user's entry did not match the image verification
2153 // Parameters: none
2154 $aMessages[MSG_ARESP_NO_MATCH] = 'Your entry did not match the image';
2155
2156 // MSG_LOG_FAILED is written to the auto respond log file
2157 // if the autoresponding failed
2158 // Parameters: none
2159 $aMessages[MSG_LOG_FAILED] = 'Failed';
2160
2161 // MSG_ARESP_FAILED is sent in an Alert message
2162 // if the autoresponding failed
2163 // Parameters: none
2164 $aMessages[MSG_ARESP_FAILED] = 'Autoresponder failed';
2165
2166 // MSG_LOG_OK is written to the auto respond log file
2167 // if the autoresponding succeeded
2168 // Parameters: none
2169 $aMessages[MSG_LOG_OK] = 'OK';
2170
2171 // MSG_THANKS_PAGE is the default page that's displayed if the
2172 // submission is successful
2173 // Parameters: none
2174 $aMessages[MSG_THANKS_PAGE] = 'Thanks! We\'ve received your information '.
2175 'and, if it\'s appropriate, we\'ll be in '.
2176 'contact with you soon.';
2177
2178 // MSG_LOAD_MODULE is sent in an alert message if a module
2179 // could not be loaded.
2180 // Parameters:
2181 // $FILE the file name
2182 // $ERROR the error message
2183 $aMessages[MSG_LOAD_MODULE] = 'Cannot load module from file \'$FILE\': $ERROR';
2184
2185 // MSG_LOAD_FMCOMPUTE is sent in an alert message if the form
2186 // specifies at least one "fmcompute" field and the FMCompute
2187 // module cannot be loaded.
2188 // Parameters:
2189 // $FILE the file name
2190 // $ERROR the error message
2191 $aMessages[MSG_LOAD_FMCOMPUTE] = 'Cannot load FMCompute module from file '.
2192 '\'$FILE\': $ERROR';
2193
2194 // MSG_REGISTER_MODULE is sent in an alert message if a module
2195 // could not register with FMCompute
2196 // Parameters:
2197 // $NAME the name of the module
2198 // $ERROR the error message
2199 $aMessages[MSG_REGISTER_MODULE] = 'Cannot register module $NAME with '.
2200 'FMCompute: $ERROR';
2201
2202
2203 // MSG_COMP_PARSE is sent in an alert message if a parse error
2204 // occurs in an fmcompute field
2205 // Parameters:
2206 // $CODE the code with an error
2207 // $ERRORS the error messages
2208 $aMessages[MSG_COMP_PARSE] = 'These parse errors occurred in the following '.
2209 'code:\n$ERRORS\n$CODE';
2210
2211 // MSG_COMP_REG_DATA is sent in an alert message if FormMail cannot
2212 // register a data field with the FMCompute module
2213 // Parameters:
2214 // $NAME the field name
2215 // $ERROR the error message
2216 $aMessages[MSG_COMP_REG_DATA] = 'Failed to register data field \'$NAME\': '.
2217 '$ERROR';
2218
2219 // MSG_COMP_ALERT is sent in an alert message if the FMCompute
2220 // module has generated some alert messages.
2221 // Parameters:
2222 // $ALERTS the alerts
2223 $aMessages[MSG_COMP_ALERT] = 'The following alert messages were reported '.
2224 'from the FMCompute module: $ALERTS';
2225
2226 // MSG_COMP_DEBUG is sent in an alert message if the FMCompute
2227 // module has generated some debug messages.
2228 // Parameters:
2229 // $DEBUG the alerts
2230 $aMessages[MSG_COMP_DEBUG] = 'The following debug messages were reported '.
2231 'from the FMCompute module: $DEBUG';
2232
2233 // MSG_COMP_EXEC is sent in an alert message if the FMCompute
2234 // module has generated some error messages during execution
2235 // Parameters:
2236 // $ERRORS the errors
2237 $aMessages[MSG_COMP_EXEC] = 'The following error messages were reported '.
2238 'from the FMCompute module: $ERRORS';
2239
2240 // MSG_REG_FMCOMPUTE is sent in an Alert message when FormMail
2241 // cannot register an external function with FMCompute.
2242 // Parameters:
2243 // FUNC the function that could not be registered
2244 // ERROR the error message
2245 $aMessages[MSG_REG_FMCOMPUTE] = 'Cannot register function "$FUNC" with '.
2246 'FMCompute: $ERROR';
2247
2248
2249 // MSG_USER_ERRORS is shown as part of a user error when an FMCompute
2250 // has called the "UserError" function one or more times.
2251 // Parameters:
2252 // NONE
2253 $aMessages[MSG_USER_ERRORS] = 'One or more errors occurred in your form submission';
2254
2255
2256 // MSG_CALL_PARAM_COUNT is sent in an alert when a call to a FormMail
2257 // function from FMCompute has the wrong number of parameters
2258 // Parameters:
2259 // FUNC the function name
2260 // COUNT the actual number of parameters passed
2261 $aMessages[MSG_CALL_PARAM_COUNT] = 'FMCompute called FormMail function '.
2262 '\'$FUNC\' with wrong number of '.
2263 'parameters: $COUNT';
2264
2265 // MSG_CALL_UNK_FUNC is sent in an alert when FMCompute calls an
2266 // unknown FormMail function
2267 // Parameters:
2268 // FUNC the function name
2269 $aMessages[MSG_CALL_UNK_FUNC] = 'FMCompute called unknown FormMail function '.
2270 '\'$FUNC\'';
2271
2272 // MSG_SAVE_FILE is sent in an alert when saving a file to
2273 // the server has failed
2274 // Parameters:
2275 // FILE the source file name (usually a temporary file name)
2276 // DEST the destination file name
2277 // ERR the error message
2278 $aMessages[MSG_SAVE_FILE] = 'Failed to save file \'$FILE\' to \'$DEST\': $ERR';
2279
2280 // MSG_CHMOD is sent in an alert when changing the protection
2281 // mode of a file to has failed
2282 // Parameters:
2283 // FILE the file name
2284 // MODE the mode
2285 // ERR the error message
2286 $aMessages[MSG_CHMOD] = 'Failed to change protection mode of file \'$FILE\' '.
2287 'to $MODE: $ERR';
2288
2289 // MSG_VERIFY_MISSING is shown to the user image verification string
2290 // was not found
2291 // Parameters: none
2292 $aMessages[MSG_VERIFY_MISSING] = 'Image verification string missing. This'.
2293 ' is probably a fault on the server.';
2294
2295 // MSG_VERIFY_MATCH is shown to the user
2296 // if the user's entry did not match the image verification for the
2297 // imgverify option
2298 // Parameters: none
2299 $aMessages[MSG_VERIFY_MATCH] = 'Your entry did not match the image';
2300
2301 // MSG_FILE_NAMES_INVALID is sent in an Alert message when
2302 // a form's file_names setting has errors
2303 // Parameters: none
2304 // A list of errors is appended on separate lines
2305 $aMessages[MSG_FILE_NAMES_INVALID] = 'Some file_names specifications are invalid $MNUM:\n';
2306
2307 // MSG_FILE_NAMES_NOT_FILE is sent in an Alert message when
2308 // a form's file_names setting refers to a file field that doesn't
2309 // exist
2310 // Parameters:
2311 // NAME the name of the file field that doesn't exist
2312 $aMessages[MSG_FILE_NAMES_NOT_FILE] = 'Your file_names specification has '.
2313 'an error. \'$NAME\' is not the name '.
2314 'of a file upload field\n';
2315
2316 // MSG_NEXT_PLUS_GOOD is sent in an alert message if the form is
2317 // ambiguous and specifies both "next_form" and "good_url" or
2318 // "good_template"
2319 // Parameters:
2320 // $WHICH the "good_" field that was specified
2321 $aMessages[MSG_NEXT_PLUS_GOOD] = 'The form has specified both "next_form" '.
2322 'and "$WHICH" fields - the action to '.
2323 'to perform is ambiguous';
2324
2325 // MSG_MULTIFORM is sent in an Alert message when a form tries
2326 // to use a multi-form template, but templates have not been configured in
2327 // formmail.php
2328 // Parameters: none
2329 $aMessages[MSG_MULTIFORM] = 'You must set either MULTIFORMDIR or MULTIFORMURL '.
2330 'in formmail.php before you can use '.
2331 'multi-page forms.';
2332
2333 // MSG_MULTIFORM_FAILED is sent in an Alert message
2334 // when processing a multi-page form template has failed.
2335 // Parameters:
2336 // NAME the template name
2337 $aMessages[MSG_MULTIFORM_FAILED] = 'Failed to process multi-page form template "$NAME"';
2338
2339 // MSG_NEED_THIS_FORM is sent in an Alert message
2340 // when a multi-page form does not specify the "this_form" field.
2341 // Parameters:
2342 // none
2343 $aMessages[MSG_NEED_THIS_FORM] = 'Multi-page forms require "this_form" field';
2344
2345 // MSG_NO_PHP_SELF is sent in an Alert message
2346 // when FormMail requires the "PHP_SELF" server variable and PHP is not
2347 // providing it.
2348 // Parameters:
2349 // none
2350 $aMessages[MSG_NO_PHP_SELF] = 'PHP on the server is not providing "PHP_SELF"';
2351
2352 // MSG_RETURN_URL_INVALID is sent in an Alert message
2353 // when "this_form" is not a valid return URL. This occurs for
2354 // multi-page forms.
2355 // Parameters:
2356 // URL the invalid URL
2357 $aMessages[MSG_RETURN_URL_INVALID] = 'Return URL "$URL" is not valid';
2358
2359 // MSG_GO_BACK is sent in an Alert message
2360 // when "multi_go_back" has been submitted but this isn't part of a
2361 // multi-page form.
2362 // Parameters:
2363 // none
2364 $aMessages[MSG_GO_BACK] = 'Cannot "go back" if not in a multi-page form '.
2365 'sequence or at the first page of the form '.
2366 'sequence';
2367
2368 // MSG_OPEN_URL is sent in an Alert message when a URL cannot
2369 // be opened.
2370 // Parameters:
2371 // URL the invalid URL
2372 // ERROR error message
2373 $aMessages[MSG_OPEN_URL] = 'Cannot open URL "$URL": $ERROR';
2374
2375 // MSG_CANNOT_RETURN is sent in an Alert message when an invalid return
2376 // request is made in a multi-page form sequence.
2377 // Parameters:
2378 // TO the requested page index
2379 // TOPINDEX the top page index
2380 $aMessages[MSG_CANNOT_RETURN] = 'Cannot return to page $TO. The top page '.
2381 'index is $TOPINDEX';
2382
2383 // MSG_ATTACK_DETECTED is sent in an Alert message when an attack on
2384 // the server has been detected
2385 // Parameters:
2386 // ATTACK name or description of the attack
2387 // INFO more information about the attack
2388 $aMessages[MSG_ATTACK_DETECTED] = 'Server attack "$ATTACK" detected. '.
2389 'Your server is safe as FormMail is '.
2390 'invulnerable to this attack. You can '.
2391 'disable these messages by setting '.
2392 'ALERT_ON_ATTACK_DETECTION to false '.
2393 'in FormMail\'s configuration section.'.
2394 '\nMore information:\n$INFO';
2395
2396 // MSG_ATTACK_PAGE is the contents of the browser page displayed to the
2397 // user when an attack is detected
2398 // Parameters:
2399 // none
2400 $aMessages[MSG_ATTACK_PAGE] = 'Your form submission has been rejected '.
2401 'as it appears to be an abuse of our server.';
2402
2403 // MSG_ATTACK_MIME_INFO is the contents of the INFO parameter
2404 // to the MSG_ATTACK_DETECTED message for the MIME attack
2405 // Parameters:
2406 // FLD name of the field
2407 // CONTENT the invalid content found in the field
2408 $aMessages[MSG_ATTACK_MIME_INFO] = 'The field "$FLD" contained invalid '.
2409 'content "$CONTENT"';
2410
2411 // MSG_ATTACK_DUP_INFO is the contents of the INFO parameter
2412 // to the MSG_ATTACK_DETECTED message for the Duplicate Data attack
2413 // Parameters:
2414 // FLD1 name of the first field
2415 // FLD2 name of the second field
2416 $aMessages[MSG_ATTACK_DUP_INFO] = 'The fields "$FLD1" and "$FLD2" contained '.
2417 'duplicate data';
2418
2419 // MSG_ATTACK_SPEC_INFO is the contents of the INFO parameter
2420 // to the MSG_ATTACK_DETECTED message for the Special Field attack
2421 // Parameters:
2422 // FLD name of the special field
2423 $aMessages[MSG_ATTACK_SPEC_INFO] = 'Special field "$FLD" contained an email address';
2424
2425 // MSG_URL_PARSE is an error message when a URL to be opened
2426 // cannot be parsed
2427 // Parameters:
2428 // none
2429 $aMessages[MSG_URL_PARSE] = 'Failed to parse URL';
2430
2431 // MSG_URL_SCHEME is an error message when a URL to be opened
2432 // has an unsupported "scheme" value
2433 // Parameters:
2434 // SCHEME the scheme that was seen
2435 $aMessages[MSG_URL_SCHEME] = 'Unsupported URL scheme "$SCHEME"';
2436
2437 // MSG_SOCKET is an error message when opening a socket for a URL
2438 // fails
2439 // Parameters:
2440 // ERRNO the error code
2441 // ERRSTR the error string
2442 // PHPERR the value of $php_errormsg
2443 $aMessages[MSG_SOCKET] = 'Socket error $ERRNO: $ERRSTR: $PHPERR';
2444
2445 // MSG_GETURL_OPEN is an error message when the web server reports
2446 // a failure on opening a URL
2447 // Parameters:
2448 // STATUS the HTTP status value (number + string)
2449 $aMessages[MSG_GETURL_OPEN] = 'Open URL failed: $STATUS';
2450
2451 // MSG_FILE_UPLOAD_ERRn are the error messages corresponding to the
2452 // PHP file upload error code n.
2453 // Parameters:
2454 // none
2455 $aMessages[MSG_FILE_UPLOAD_ERR1] = 'The uploaded file exceeds the upload_max_filesize directive in php.ini.';
2456 $aMessages[MSG_FILE_UPLOAD_ERR2] = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.';
2457 $aMessages[MSG_FILE_UPLOAD_ERR3] = 'The uploaded file was only partially uploaded.';
2458 $aMessages[MSG_FILE_UPLOAD_ERR4] = 'No file was uploaded.';
2459
2460 // MSG_FILE_UPLOAD_ERR_UNK is displayed when an unknown error code
2461 // is provided by PHP for a file upload
2462 // Parameters:
2463 // ERRNO the error code
2464 $aMessages[MSG_FILE_UPLOAD_ERR_UNK] = 'Unknown file upload error code $ERRNO';
2465
2466 // MSG_FILE_UPLOAD_SIZE is displayed when an uploaded file exceeds
2467 // the configured maximum size
2468 // Parameters:
2469 // NAME the uploaded file's name
2470 // SIZE the size of the uploaded file
2471 // MAX the maximum size that was exceeded
2472 $aMessages[MSG_FILE_UPLOAD_SIZE] = 'Uploaded file "$NAME" is too big ('.
2473 '$SIZE bytes). The maximum permitted '.
2474 'size is $MAX kilobytes.';
2475
2476 // MSG_DER_FUNC_ERROR is sent in an Alert message when
2477 // a form uses a derive_fields function that's
2478 // formatted incorrectly
2479 // Parameters:
2480 // $SPEC the invalid value specification
2481 // $MSG a message describing the error or providing an example
2482 $aMessages[MSG_DER_FUNC_ERROR] = 'derive_fields: invalid function specification '.
2483 '"$SPEC": $MSG';
2484
2485 // MSG_DER_FUNC_SIZE_FMT describes the right syntax for the "size" function
2486 // Parameters:
2487 // none
2488 $aMessages[MSG_DER_FUNC_SIZE_FMT] = '"size" function requires this format: '.
2489 'size(file_field)';
2490
2491 // MSG_DER_FUNC_IF_FMT describes the right syntax for the "if" function
2492 // Parameters:
2493 // none
2494 $aMessages[MSG_DER_FUNC_IF_FMT] = '"if" function requires this format: '.
2495 'if(field;spec;spec)';
2496
2497} // <A NAME="BuiltinMessages"> Jump to: <A HREF="#MessageNumbers">
2498
2499 //
2500 // Load the default language, and then override with an optional language file.
2501 //
2502function LoadLanguage()
2503{
2504 LoadBuiltinLanguage();
2505 LoadLanguageFile();
2506}
2507
2508 //
2509 // To return the value of a string or empty string if not set.
2510 //
2511function CheckString($ss)
2512{
2513 return (isset($ss) ? $ss : "");
2514}
2515
2516$aGetMessageSubstituteErrors = array();
2517$aGetMessageSubstituteFound = array();
2518$bGetMessageSubstituteNoErrors = false;
2519
2520 //
2521 // Worker function for GetMessage's preg_replace_callback calls.
2522 // Returns the value of the matched variable name.
2523 // Variables are searched for in the global $aGetMessageValues.
2524 // If no such variable exists, an empty string is returned and the
2525 // global variable $aGetMessageSubstituteErrors lists the missing names.
2526 //
2527function GetMessageSubstituteParam($a_matches)
2528{
2529 global $aGetMessageValues,$aGetMessageSubstituteErrors;
2530 global $aGetMessageSubstituteFound,$bGetMessageSubstituteNoErrors;
2531
2532 $s_name = $a_matches[1];
2533 $aGetMessageSubstituteFound[] = $s_name;
2534 $s_value = "";
2535 if (isset($aGetMessageValues[$s_name]))
2536 $s_value = $aGetMessageValues[$s_name];
2537 elseif ($bGetMessageSubstituteNoErrors)
2538 $s_value = '$'.$s_name;
2539 else
2540 $aGetMessageSubstituteErrors[] = $s_name;
2541 return ($s_value);
2542}
2543
2544 //
2545 // Returns message text from a message number, with optional parameters.
2546 //
2547function GetMessage($i_msg_num,$a_params = array(),
2548 $b_show_mnum = true,$b_no_errors = false)
2549{
2550 global $aMessages,$sLangID,$bShowMesgNumbers;
2551
2552 if (!isset($aMessages[$i_msg_num]))
2553 {
2554 SendAlert("Unknown Message Number $i_msg_num was used",false,true);
2555 $s_text = "<UNKNOWN MESSAGE NUMBER>";
2556 }
2557 else
2558 $s_text = $aMessages[$i_msg_num];
2559 $s_mno = $bShowMesgNumbers ? "[M$i_msg_num]" : "";
2560
2561 //
2562 // substitute parameters; only works with PHP version 4.0.5 or later
2563 //
2564 if (strpos($s_text,'$') !== false)
2565 {
2566 global $aGetMessageValues,$aGetMessageSubstituteErrors;
2567 global $aGetMessageSubstituteFound,$bGetMessageSubstituteNoErrors;
2568
2569 $aGetMessageSubstituteErrors = array();
2570 $aGetMessageSubstituteFound = array();
2571 $aGetMessageValues = $a_params;
2572 $bGetMessageSubstituteNoErrors = $b_no_errors;
2573 $aGetMessageValues["MNUM"] = $s_mno; // add the message number
2574 //
2575 // search for words in this form:
2576 // $word
2577 // where word begins with an alphabetic character and
2578 // consists of alphanumeric and underscore
2579 //
2580 $s_text = preg_replace_callback('/\$([a-z][a-z0-9_]*)/i',
2581 'GetMessageSubstituteParam',$s_text);
2582 if (count($aGetMessageSubstituteErrors) > 0)
2583 SendAlert("Message Number $i_msg_num in language $sLangID ".
2584 "specified the following unsupported parameters: ".
2585 implode(',',$aGetMessageSubstituteErrors));
2586 if (!in_array("MNUM",$aGetMessageSubstituteFound))
2587 //
2588 // append the message number
2589 //
2590 $s_text .= $b_show_mnum ? " $s_mno" : "";
2591 }
2592 else
2593 //
2594 // append the message number
2595 //
2596 $s_text .= $b_show_mnum ? " $s_mno" : "";
2597 //
2598 // replace '\n' sequences with new lines
2599 //
2600 return (str_replace('\n',"\n",$s_text));
2601}
2602
2603 //
2604 // Check for old version of PHP - die if too old.
2605 //
2606function IsOldVersion(&$a_this_version)
2607{
2608 $a_modern = array(4,1,0); // versions prior to this are "old" - "4.1.0"
2609 $s_req_string = "4.0.5"; // version 4.0.5 of PHP is required from
2610 // FormMail 5.00 onward (because we use
2611 // preg_replace_callback for all messages to
2612 // support languages other than English)
2613 $a_too_old = explode(".",$s_req_string);
2614
2615 $i_cannot_use = ($a_too_old[0] * 10000) +
2616 ($a_too_old[1] * 100) +
2617 $a_too_old[2];
2618
2619 $s_vers_string = phpversion();
2620 $a_this_version = explode(".",$s_vers_string);
2621 $i_this_num = ($a_this_version[0] * 10000) +
2622 ($a_this_version[1] * 100) +
2623 $a_this_version[2];
2624
2625 if ($i_this_num <= $i_cannot_use)
2626 die(GetMessage(MSG_SCRIPT_VERSION,array("PHPREQ"=>$s_req_string,
2627 "PHPVERS"=>$s_vers_string)));
2628 $i_modern_num = ($a_modern[0] * 10000) +
2629 ($a_modern[1] * 100) +
2630 $a_modern[2];
2631 return ($i_this_num < $i_modern_num);
2632}
2633
2634 //
2635 // Check if the server is Windows
2636 //
2637function IsServerWindows()
2638{
2639 static $bGotAnswer = false;
2640 static $bAnswer;
2641
2642 if (!$bGotAnswer)
2643 {
2644 if ((isset($_ENV["OS"]) && stristr($_ENV["OS"],"windows") !== false) ||
2645 (isset($_SERVER["PATH"]) && stristr($_SERVER["PATH"],"winnt") !== false) ||
2646 (isset($_SERVER["PATH"]) && stristr($_SERVER["PATH"],"windows") !== false) ||
2647 (isset($_SERVER["SystemRoot"]) && stristr($_SERVER["SystemRoot"],"winnt") !== false) ||
2648 (isset($_ENV["SystemRoot"]) && stristr($_ENV["SystemRoot"],"winnt") !== false) ||
2649 (isset($_SERVER["SystemRoot"]) && stristr($_SERVER["SystemRoot"],"windows") !== false) ||
2650 (isset($_ENV["SystemRoot"]) && stristr($_ENV["SystemRoot"],"windows") !== false) ||
2651 (isset($_SERVER["Path"]) && stristr($$_SERVER["Path"],"windows") !== false))
2652 $bAnswer = true;
2653 else
2654 $bAnswer = false;
2655 $bGotAnswer = true;
2656 }
2657 return ($bAnswer);
2658}
2659
2660 //
2661 // To return a temporary file name.
2662 //
2663function GetTempName($s_prefix)
2664{
2665 global $SCRATCH_PAD;
2666
2667 if (isset($SCRATCH_PAD) && !empty($SCRATCH_PAD))
2668 {
2669 switch (substr($SCRATCH_PAD,-1))
2670 {
2671 case '/':
2672 case '\\':
2673 $s_dir = substr($SCRATCH_PAD,0,-1);
2674 break;
2675 default:
2676 $s_dir = $SCRATCH_PAD;
2677 break;
2678 }
2679 //
2680 // Ideally, we could use tempnam. But,
2681 // tempnam is system dependent and might not use the
2682 // SCRATCH_PAD directory even if we tell it to.
2683 // So, we'll force the file into SCRATCH_PAD.
2684 //
2685 // Note that we do *not* create the file, even though tempnam
2686 // does create it in PHP version 4.0.3 and above. (The reason is
2687 // we can't guarantee a non-race condition anyway.)
2688 //
2689 do
2690 {
2691 $i_rand = mt_rand(0,16777215); // 16777215 is FFFFFF in hex
2692 $s_name = $SCRATCH_PAD."/".$s_prefix.sprintf("%06X",$i_rand);
2693 }
2694 while (file_exists($s_name));
2695 }
2696 else
2697 $s_name = tempnam("/tmp",$s_prefix);
2698 return ($s_name);
2699}
2700
2701 //
2702 // To find a directory on the server for temporary files.
2703 //
2704function GetTempDir()
2705{
2706 $s_name = GetTempName("fm");
2707 if (file_exists($s_name))
2708 unlink($s_name);
2709 $s_dir = dirname($s_name);
2710 return ($s_dir);
2711}
2712
2713 //
2714 // Returns true if the PHP version is at or later than the string specified
2715 // (can't use "version_compare" before 4.1.0).
2716 //
2717function IsPHPAtLeast($s_vers)
2718{
2719 global $aPHPVERSION;
2720
2721 $a_test_version = explode(".",$s_vers);
2722 if (count($a_test_version) < 3)
2723 return (false);
2724 return ($aPHPVERSION[0] > $a_test_version[0] ||
2725 ($aPHPVERSION[0] == $a_test_version[0] &&
2726 ($aPHPVERSION[1] > $a_test_version[1] ||
2727 $aPHPVERSION[1] == $a_test_version[1] &&
2728 $aPHPVERSION[2] >= $a_test_version[2])));
2729}
2730
2731define('DEBUG',false); // for production
2732//define('DEBUG',true); // for development and debugging
2733
2734if (DEBUG)
2735{
2736 error_reporting(E_ALL); // trap everything!
2737 LoadLanguage();
2738}
2739else
2740{
2741 $iOldLevel = error_reporting(E_ALL ^ E_WARNING);
2742 LoadLanguage();
2743 //
2744 // report everyting except warnings and notices
2745 //
2746 error_reporting(E_ALL ^ E_WARNING ^ E_NOTICE);
2747}
2748
2749$bUseOldVars = IsOldVersion($aPHPVERSION);
2750
2751 //
2752 // seed the random number generate if not version 4.2.0 or later
2753 //
2754if (!IsPHPAtLeast("4.2.0"))
2755 mt_srand(time());
2756
2757 //
2758 // we set references to the appropriate arrays to handle PHP version differences
2759 // Session vars are selected after we start the session.
2760 //
2761if ($bUseOldVars)
2762{
2763 $aServerVars = &$HTTP_SERVER_VARS;
2764 $aGetVars = &$HTTP_GET_VARS;
2765 $aFormVars = &$HTTP_POST_VARS;
2766 $aFileVars = &$HTTP_POST_FILES;
2767 $aEnvVars = &$HTTP_ENV_VARS;
2768}
2769else
2770{
2771 $aServerVars = &$_SERVER;
2772 $aGetVars = &$_GET;
2773 $aFormVars = &$_POST;
2774 $aFileVars = &$_FILES;
2775 $aEnvVars = &$_ENV;
2776}
2777$bIsGetMethod = false;
2778
2779 //
2780 // If the form submission was using the GET method, switch to the
2781 // GET vars instead of the POST vars
2782 //
2783if (isset($aServerVars["REQUEST_METHOD"]) && $aServerVars["REQUEST_METHOD"] === "GET")
2784{
2785 $bIsGetMethod = true;
2786 if ($bUseOldVars)
2787 $aFormVars = &$HTTP_GET_VARS;
2788 else
2789 $aFormVars = &$_GET;
2790}
2791
2792function SetRealDocumentRoot()
2793{
2794 global $aServerVars,$REAL_DOCUMENT_ROOT;
2795
2796 if (isset($aServerVars['SCRIPT_FILENAME']))
2797 $REAL_DOCUMENT_ROOT = $aServerVars['SCRIPT_FILENAME'];
2798 elseif (isset($aServerVars['PATH_TRANSLATED']))
2799 $REAL_DOCUMENT_ROOT = $aServerVars['PATH_TRANSLATED'];
2800 else
2801 $REAL_DOCUMENT_ROOT = "";
2802 //
2803 // look for 'www' or 'public_html' and strip back to that if found,
2804 // otherwise just get the directory name
2805 //
2806 if (($i_pos = strpos($REAL_DOCUMENT_ROOT,"/www/")) !== false)
2807 $REAL_DOCUMENT_ROOT = substr($REAL_DOCUMENT_ROOT,0,$i_pos+4);
2808 elseif (($i_pos = strpos($REAL_DOCUMENT_ROOT,"/public_html/")) !== false)
2809 $REAL_DOCUMENT_ROOT = substr($REAL_DOCUMENT_ROOT,0,$i_pos+12);
2810 elseif (!empty($REAL_DOCUMENT_ROOT))
2811 $REAL_DOCUMENT_ROOT = dirname($REAL_DOCUMENT_ROOT);
2812 elseif (isset($aServerVars['DOCUMENT_ROOT']) &&
2813 !empty($aServerVars['DOCUMENT_ROOT']))
2814 $REAL_DOCUMENT_ROOT = $aServerVars['DOCUMENT_ROOT'];
2815}
2816
2817if (!isset($REAL_DOCUMENT_ROOT))
2818 SetRealDocumentRoot();
2819
2820if (isset($aServerVars['SERVER_PORT']))
2821 $SCHEME = ($aServerVars['SERVER_PORT'] == 80) ? "http://" : "https://";
2822else
2823 $SCHEME = "";
2824if (isset($aServerVars['SERVER_NAME']))
2825 $SERVER = $aServerVars['SERVER_NAME'];
2826else
2827 $SERVER = "";
2828
2829/*****************************************************************************/
2830/* CONFIGURATION (do not alter this line in any way!!!) */
2831/*****************************************************************************
2832 * This is the *only* place where you need to modify things to use formmail.php
2833 * on your particular system. This section finishes at "END OF CONFIGURATION".
2834 *
2835 * Each variable below is marked as LEAVE, OPTIONAL or MANDATORY.
2836 * What we mean is:
2837 * LEAVE you can change this if you really want to and know what
2838 * you're doing, but we recommend that you leave it unchanged
2839 *
2840 * OPTIONAL you can change this if you need to, but its current
2841 * value is fine and we recommend that you leave it unchanged
2842 * unless you need a different value
2843 *
2844 * MANDATORY you *must* modify this for your system. The script will
2845 * not work if you don't set the value correctly.
2846 *
2847 *****************************************************************************/
2848
2849 //
2850 // ** LEAVE **
2851 // EMAIL_NAME is a limited set of characters that you can use for your
2852 // target email user names (the text before the "@");
2853 // these are accepted:
2854 // russellr
2855 // russ.robinson
2856 // russ61robbo
2857 //
2858 // The pattern we've provided doesn't match every valid user name in an
2859 // email address, but, since these email addresses are ones you'll
2860 // choose and are part of your organisation, the limited set is generally
2861 // no problem.
2862 //
2863 // If you want to use other user names, then you need to change the pattern
2864 // accordingly.
2865 //
2866 // We recommend that you don't modify this pattern, but, rather, use
2867 // conforming email user names as your target email addresses.
2868 // BTW, the pattern is processed case-insensitively, so there's
2869 // no need to provide upper and lower case values.
2870 //
2871define("EMAIL_NAME","^[-a-z0-9.]+"); // the '^' is an important security feature!
2872
2873 //
2874 // ** MANDATORY **
2875 // Set TARGET_EMAIL to a list of patterns that callers are allowed
2876 // to send mail to; this is a *critical* security mechanism and
2877 // prevents relaying. Relaying is where an unauthorized person uses this
2878 // script to send mail to *anyone* in the world.
2879 //
2880 // By setting TARGET_EMAIL to a set of patterns for your email addresses,
2881 // then relaying is prevented.
2882 //
2883 // More information about TARGET_EMAIL.
2884 //
2885 // Instructions
2886 // ~~~~~~~~~~~~
2887 // 1. If you only have one host or domain name:
2888 // replace "yourhost" with the name of your email server computer.
2889 // For example,
2890 // EMAIL_NAME."@yourhost\.com$"
2891 // becomes:
2892 // EMAIL_NAME."@microsoft\.com$"
2893 // If you work for Microsoft (microsoft.com).
2894 //
2895 // 2. If you have a domain name other than ".com":
2896 // replace "yourhost\.com" with your email server's full
2897 // domain name.
2898 // For example,
2899 // EMAIL_NAME."@yourhost\.com$"
2900 // becomes:
2901 // EMAIL_NAME."@apache\.org$"
2902 // If you work for the Apache organisation (apache.org).
2903 // Another example is:
2904 // EMAIL_NAME."@rootsoftware\.com\.au$"
2905 // If you work for Root Software in Australia (rootsoftware.com.au).
2906 //
2907 // 3. If you want to accept email to several domains, you can do that too.
2908 // Here's an example. At Root Software, our forms can send to any of
2909 // the following domains:
2910 // rootsoftware.com
2911 // rootsoftware.com.au
2912 // ttmaker.com
2913 // timetabling.org
2914 // timetabling-scheduling.com
2915 // tectite.com
2916 // To achieve this, we have the following setting:
2917 // $TARGET_EMAIL = array(EMAIL_NAME."@rootsoftware\.com$",
2918 // EMAIL_NAME."@rootsoftware\.com\.au$",
2919 // EMAIL_NAME."@ttmaker\.com$",
2920 // EMAIL_NAME."@timetabling\.org$",
2921 // EMAIL_NAME."@timetabling-scheduling\.com$",
2922 // EMAIL_NAME."@tectite\.com$",
2923 // );
2924 //
2925 // 4. If you want to accept email to several specific email addresses,
2926 // that's fine too. Here's an example:
2927 // $TARGET_EMAIL = array("^russell\.robinson@rootsoftware\.com$",
2928 // "^info@ttmaker\.com$",
2929 // "^sales@timetabling\.org$",
2930 // "^webmaster@timetabling-scheduling\.com$",
2931 // );
2932 // or just one email address:
2933 // $TARGET_EMAIL = array("^russell\.robinson@rootsoftware\.com$");
2934 //
2935 //
2936 // More Instructions
2937 // ~~~~~~~~~~~~~~~~~
2938 // TARGET_EMAIL is an array. This means it can contain many "elements".
2939 // Each element is a string (a set of characters in quotes).
2940 // To create many elements, you simply list the strings separated by
2941 // a comma.
2942 // For example:
2943 // $TARGET_EMAIL = array("String 1","String 2","String 3");
2944 //
2945 // You can put a newline after each comma, to make it more readable.
2946 // Like this:
2947 // $TARGET_EMAIL = array("String 1",
2948 // "String 2",
2949 // "String 3");
2950 //
2951 // If you look below, you may be wondering why you can see the following:
2952 // EMAIL_NAME."@yourhost\.com$"
2953 // and that's not a string!
2954 //
2955 // It's a string concatenation. EMAIL_NAME is a string (and you can
2956 // see it defined above), and the "." after it says "append the following
2957 // string to EMAIL_NAME and make one larger string".
2958 //
2959 // So,
2960 // EMAIL_NAME."@yourhost\.com$"
2961 // becomes the string:
2962 // "^[-a-z0-9.]+@yourhost\.com$"
2963 //
2964 // What are all the \ ^ $ and other punctuation characters?
2965 //
2966 // The strings we're defining contain "patterns". We won't go into
2967 // patterns here (it's a large subject), but we will explain a few
2968 // important things:
2969 // ^ means the beginning; we want email user names to match only
2970 // at the beginning of the input, so that's why EMAIL_NAME starts
2971 // with ^
2972 // . matches any single character
2973 // \ stops the following character from being a pattern matcher
2974 // $ matches the end
2975 //
2976 // So, when we want to match ".com", we need to say "\.com". Otherwise,
2977 // ".com" would match "Xcom", "Ycom", "xcom", etc., as well as ".com".
2978 // The "\." says match only ".".
2979 //
2980 // Also, if your server is "yourhost.com", you don't want to match
2981 // "yourhost.com.anythingelse", so we put "yourhost\.com$" to match
2982 // the end.
2983 //
2984 // Note: if you're going to send to a domain that you don't own (e.g.
2985 // yahoo.com or hotmail.com), *DO NOT* use the EMAIL_NAME feature.
2986 // If you do, then your installation of FormMail could become a
2987 // spam gateway! Instead, specify exact email addresses using one
2988 // of the examples below.
2989 //
2990 // For security purposes, it's best to include ^ at the start and
2991 // $ at the end of all email address patterns. This will prevent spammers
2992 // from exploiting any vulnerabilities in your server or its software.
2993 //
2994 // Finally, don't use your AT_MANGLE (see below) characters here.
2995 // The $TARGET_EMAIL needs to look like a real email address or pattern.
2996 // You must use "@". Don't worry, spammers can't see inside formmail.php
2997 // so they can't get the email addresses or patterns you put in $TARGET_EMAIL.
2998 //
2999$TARGET_EMAIL = array("^info@waterworldusa\.com$");
3000 //
3001 // here are some other examples...
3002 //
3003//$TARGET_EMAIL = array("^yourname@yourhost\.com$");
3004//$TARGET_EMAIL = array("^yourname@yourhost\.com$","^someone@yourhost\.com$");
3005//$TARGET_EMAIL = array(EMAIL_NAME."@yourhost\.com$",EMAIL_NAME."@otherhost\.com$");
3006
3007 //
3008 // ** OPTIONAL BUT STRONGLY RECOMMENDED **
3009 // Set DEF_ALERT to the email address that will be sent any alert
3010 // messages (such as errors) from the script. This value is
3011 // only used if the 'alert_to' is not provided by the form.
3012 // If neither alert_to nor DEF_ALERT are provided, no alerts are sent.
3013 //
3014 // DEF_ALERT can be any email address and it's independent of
3015 // the TARGET_EMAIL setting.
3016 //
3017 // Example:
3018 // webmaster@yourhost.com
3019 //
3020 // If you set DEF_ALERT, you can do some initial tests with your browser.
3021 // Just open this URL:
3022 // http://www.your-site.com/formmail.php?testalert=1
3023 //
3024//define("DEF_ALERT","you@yoursite.com"); // example - straight email address
3025define("DEF_ALERT","sal@waterworldusa.com");
3026
3027 //
3028 // ** OPTIONAL **
3029 // SET_REAL_DOCUMENT_ROOT tells FormMail the DocumentRoot for your website.
3030 //
3031 // Automatically finding the document root for your website in PHP can be
3032 // quite problematical. $_SERVER["DOCUMENT_ROOT"] is often correct,
3033 // but sometimes it's not provided (e.g. with a CGI interface) and with
3034 // certain secure server configurations, it's completely inappropriate.
3035 //
3036 // For example, our website at http://www.tectite.com/ also lives
3037 // at https://secure.rootsoftware.com/~tectite/. If we run FormMail
3038 // from the latter location (such as when you place an order)
3039 // $_SERVER["DOCUMENT_ROOT"] is set to "/home/secure" - which is completely
3040 // wrong and won't work.
3041 //
3042 // The function above - SetRealDocumentRoot - is designed to set
3043 // $REAL_DOCUMENT_ROOT to the right value based on the setting
3044 // of SCRIPT_FILENAME or PATH_TRANSLATED (or as a last attempt, DOCUMENT_ROOT).
3045 //
3046 // SetRealDocumentRoot should work on most servers in most situations.
3047 // However, it might not work on your server. Therefore, you can set
3048 // $SET_REAL_DOCUMENT_ROOT to the correct value for your website.
3049 // Use an absolute directory pathname such as:
3050 //
3051 // /home/yourname/public_html
3052 // d:/inet/user/htdocs
3053 //
3054 // NOTE: on Windows servers, use '/' instead of '\' or double the
3055 // '\' like this:
3056 // "d:\\path\\to\\document_root"
3057 // or
3058 // "d:/path/to/document_root"
3059 //
3060 // If you're not using the "filter" feature in your forms, you don't
3061 // need to worry about these settings.
3062 //
3063$SET_REAL_DOCUMENT_ROOT = ""; // overrides the value set by SetRealDocumentRoot function
3064
3065 //
3066 // override $REAL_DOCUMENT_ROOT from the $SET_REAL_DOCUMENT_ROOT value (if any)
3067 // Do not alter the following code (next 3 lines)!
3068 //
3069if (isset($SET_REAL_DOCUMENT_ROOT) && $SET_REAL_DOCUMENT_ROOT !== "")
3070 $REAL_DOCUMENT_ROOT = $SET_REAL_DOCUMENT_ROOT;
3071
3072 //
3073 // ** OPTIONAL **
3074 // CONFIG_CHECK tells FormMail which configuration variables to check.
3075 //
3076 // Currently, only TARGET_EMAIL is checked and it is tested for
3077 // the best known patterns for securing your FormMail installation.
3078 //
3079 // If you're sure you've got your configuration correct and want to
3080 // stop warnings you are receiving in alert messages, you can
3081 // remove the name of the configuration variable you *don't* want
3082 // checked from the CONFIG_CHECK array.
3083 //
3084$CONFIG_CHECK = array("TARGET_EMAIL");
3085
3086 //
3087 // ** OPTIONAL **
3088 // Set AT_MANGLE to a string to replace with "@". To disable this
3089 // feature, set to empty string.
3090 //
3091 // If you enable this feature, you can protect the email addresses
3092 // you specify in your forms from SpamBots.
3093 //
3094 // SpamBots are programs that search for email addresses on the
3095 // Internet. Typically, they look for "mailto:someone@somewhere".
3096 //
3097 // However, email addresses you specify in your forms will be like
3098 // this:
3099 // <input type="hidden" name="recipients" value="someone@yourhost.com">
3100 //
3101 // It is possible that some SpamBots will find your email addresses hidden
3102 // in your forms.
3103 //
3104 // The AT_MANGLE feature allows you to mangle your email addresses and
3105 // protect them from SpamBots.
3106 //
3107 // Here's an example:
3108 // define("AT_MANGLE","_*_");
3109 //
3110 // This tells formmail.php to replace "_*_" in your email address with "@".
3111 // So, in your forms you can specify:
3112 // <input type="hidden" name="recipients" value="someone_*_yourhost.com">
3113 //
3114 // No SpamBot will recognize this as an email address, and your addresses
3115 // will be safe!
3116 //
3117 // If you use this feature, we encourage you to be creative and different
3118 // from everyone else.
3119 //
3120 // Here are some more examples:
3121 // define("AT_MANGLE","_@_"); // e.g. john_@_yourhost.com
3122 // // SpamBots may recognize this,
3123 // // but it'll be an invalid address
3124 //
3125 // define("AT_MANGLE","AT"); // e.g. johnATyourhost.com
3126 //
3127 // Note that the AT_MANGLE pattern match is case-sensitive, so "AT" is
3128 // different from "at".
3129 //
3130define("AT_MANGLE","DBHAA");
3131
3132 //
3133 // ** OPTIONAL **
3134 // Set TARGET_URLS to a list of URL prefixes that are acceptable.
3135 // TARGET_URLS is used for the "crm_url" feature and for multi-page
3136 // forms.
3137 // No pattern matching is allowed, and all comparisons are
3138 // performed by first converting to lower case.
3139 //
3140$TARGET_URLS = array(); // default; no URLs allowed
3141
3142// The following example allows one URL. NOTE: the trailing '/' is important
3143// for security! It prevents attackers from specifying port numbers.
3144//$TARGET_URLS = array("http://www.yourhost.com/")
3145
3146// The following example specifies a number of URLs.
3147//$TARGET_URLS = array( "http://www.yourhost.com/",
3148// "http://www.someotherhost.com/",
3149// "http://www.specialplace.com:81/");
3150
3151 //
3152 // ** LEAVE **
3153 // HEAD_CRLF is the line termination for email header lines. The email
3154 // standard (RFC-822) specifies line termination should be CR plus LF.
3155 //
3156 // Many mail systems will work with just LF and some are reported to
3157 // actually fail if the email conforms to the standard (with CR+LF).
3158 //
3159 // If you have special requirements you can change HEAD_CRLF to another
3160 // string (such as "\n" to just get LF (line feed)), but be warned that
3161 // this may break the email standard.
3162 //
3163 // Note: the following information was reported by a customer, which he
3164 // found on php.net:
3165 // "If you're using Postfix for SMTP on FreeBSD you MUST end header
3166 // lines with \n and not \r\n."
3167 // The relevant URL is: http://php.net/mail
3168 //
3169define("HEAD_CRLF","\r\n");
3170
3171 //
3172 // ** OPTIONAL **
3173 // BODY_LF is the line termination for email body lines. The email
3174 // standard (RFC-822) does not clearly specify line termination for the body
3175 // of emails; the body doesn't have to have any "lines" at all. However,
3176 // it does allow CR+LF between sections of text in the body.
3177 //
3178 // RFC-821 specifies a line length that must be supported of 998 octets
3179 // (1000 include the CR+LF).
3180 //
3181 // Most mail systems will work with just LF and that used to be the default
3182 // for FormMail prior to version 2.00.
3183 //
3184 // With the implementation of HTML template support (using MIME RFC-2045)
3185 // we've changed the default to CR+LF.
3186 //
3187 // If you want your email bodies to be line terminated differently, you
3188 // can specify a different value below.
3189 //
3190 // To change the setting, you must comment out the "define" line you
3191 // don't want (put '//' at the beginning of the line) and un-comment
3192 // the line you do want (remove '//' from the beginning of the line).
3193 //
3194//define("BODY_LF","\n"); // the old default: just LF
3195define("BODY_LF","\r\n"); // the new default: use this for CR+LF
3196
3197 //
3198 // ** OPTIONAL **
3199 // Set FROM_USER to the email address that will be the sender
3200 // of alert/error messages and Auto Responses (if used).
3201 // If you do not specify FROM_USER (that is, you comment it out),
3202 // formmail.php uses "FormMail@SERVER" where SERVER is determined
3203 // from your web server. If you set it to "NONE", then no sender is
3204 // specified.
3205 // NOTE: FROM_USER is not used for form results, it is only used
3206 // for alert messages and Auto Responses.
3207 //
3208//$FROM_USER = "formmail@yourhost.com"; // example - replace with your email address
3209//$FROM_USER = "NONE"; // use this to show no sender
3210$FROM_USER = ""; // the default - setting not used
3211
3212 //
3213 // ** LEAVE **
3214 // SENDMAIL_F_OPTION controls whether to use the "-f" option when
3215 // sending mail. Some servers use a Mail Transfer Agent called "sendmail"
3216 // and some of these require the "-f" option to be provided - this option
3217 // tells sendmail the "From" user or sender.
3218 // FormMail originally supported this feature using the "mail_options"
3219 // setting inside your HTML forms. That was a silly place for us to
3220 // put this feature! It's a server configuration, so it should live
3221 // in this configuration section of FormMail, not in your forms.
3222 //
3223 // Set SENDMAIL_F_OPTION to true to tell FormMail to specify the "-f"
3224 // option when sending mail or set it to false to prevent FormMail
3225 // from specifying it.
3226 //
3227 // Now this gets a little complicated....
3228 // FormMail distinguishes between the "From" address and the "sender".
3229 // The "sender" is used by SENDMAIL_F_OPTION. The "From" address is not.
3230 //
3231 // For form results:
3232 // The "From" address for form results is usually the email address
3233 // entered by the user on the form (the "email" field). If you set
3234 // FromAddr in mail_options, the "From" address is set to this value
3235 // and the "sender" is also set to this value. If you do not set
3236 // FromAddr, then the "From" address is set to the "email" field
3237 // (plus the "realname" field) from the form and there is no "sender".
3238 //
3239 // For alert messages:
3240 // Both "From" address and "sender" are set according to the
3241 // rules for the $FROM_USER configuration (see above).
3242 //
3243 // Following is a complete description of the emailing logic. This logic
3244 // is quite complicated because different servers have different and,
3245 // often, conflicting requirements.
3246 //
3247 // We define these concepts:
3248 // Sender is an email address that is deemed to be sending
3249 // an email.
3250 // From Line is an email address that is deemed to be the
3251 // "From" address in an email being sent.
3252 //
3253 // For Form Results (see below for Alert Messages and Auto Responses):
3254 // If the "FromAddr" feature is used by the form, then:
3255 // 1. Set Sender to the FromAddr value; and
3256 // 2. Set From Line to FromAddr value.
3257 // If the "FromAddr" feature is not used by the form, then:
3258 // 1. If SET_SENDER_FROM_EMAIL is set to true, then
3259 // Set Sender to the "email" value from the form,
3260 // otherwise,
3261 // leave Sender unset; and
3262 // 2. Set From Line to the realname + email fields from
3263 // the form.
3264 //
3265 // For Alert Messages and Auto Responses (see above for Form Results):
3266 // if FROM_USER (in FormMail's configuration) is set and is not
3267 // empty, then:
3268 // if has the value "NONE", then:
3269 // do not set either Sender or From Line values
3270 // otherwise:
3271 // set Sender and From Line values to the FROM_USER value;
3272 // if FROM_USER is not set or it's empty, then:
3273 // set Sender and From Line values to a fake address on the
3274 // server (FormMail@domain).
3275 //
3276 // For all emails (form results, alerts and auto responses):
3277 // If SENDMAIL_F_OPTION is true:
3278 // if Sender is set, specify its value with the -f option
3279 // in the mail command.
3280 // If INI_SET_FROM is true:
3281 // if Sender is set, specify its value to the "sendmail_from"
3282 // PHP option.
3283 // In every case:
3284 // set the "From:" field of the email to the value of From Line.
3285 //
3286define("SENDMAIL_F_OPTION",false);
3287define("SENDMAIL_F_OPTION_LINE",__LINE__-1); // don't modify this line!
3288
3289 //
3290 // ** LEAVE **
3291 // SET_SENDER_FROM_EMAIL controls whether the "Sender" is set from the
3292 // email field.
3293 //
3294 // Some servers require a Sender to be specified for emails sent.
3295 // If your server requires this and you do not want to use the
3296 // FromAddr feature for form results, set SET_SENDER_FROM_EMAIL
3297 // to true.
3298 //
3299 // You may also need to set SENDMAIL_F_OPTION to true.
3300 //
3301 // Review the email logic description above the SENDMAIL_F_OPTION
3302 // configuration setting for full details.
3303 //
3304 // Note that SET_SENDER_FROM_EMAIL is not used if the form specifies
3305 // FromAddr.
3306 //
3307define("SET_SENDER_FROM_EMAIL",false);
3308
3309 //
3310 // ** LEAVE **
3311 // INI_SET_FROM controls whether FormMail attempts to set the
3312 // "sendmail_from" feature in the PHP configuration. This PHP
3313 // feature only applies to Windows servers.
3314 // You can find this feature inside the "php.ini" file. On most servers
3315 // it will be set correctly and you don't need to change it.
3316 // However, some servers have this set incorrectly in php.ini and this
3317 // prevents PHP scripts from sending mail!
3318 //
3319 // Set INI_SET_FROM to true to request FormMail to set this PHP
3320 // feature to the sender of the emails it sends. You may also
3321 // need to set $FROM_USER in this configuration section (for alert messages)
3322 // and use the FromAddr feature in "mail_options" in your forms (for
3323 // sending form results). However, test each case individually.
3324 //
3325 // INI_SET_FROM sets the sender according to the documentation shown
3326 // above for SENDMAIL_F_OPTION. This means that if you need
3327 // INI_SET_FROM set to true, then you must also either require the "email"
3328 // field on a form or specify the FromAddr in the "mail_options" on
3329 // the form.
3330 //
3331 // Review the email logic description above the SENDMAIL_F_OPTION
3332 // configuration setting for full details.
3333 //
3334define("INI_SET_FROM",false);
3335
3336 //
3337 // ** OPTIONAL **
3338 // Set LOGDIR to the directory on your server where log files are
3339 // stored. When the form provides a 'logfile' value, formmail.php
3340 // expects the file to be in this directory.
3341 // Generally you want this to be outside your server's WWW directory.
3342 // For example, if your server's root (WWW) directory is:
3343 // /home/yourname/www
3344 // use a directory like
3345 // /home/yourname/logs
3346 //
3347 // If you don't want to support log files, make this an empty string:
3348 // $LOGDIR = "";
3349 //
3350 // The log file simply contains a log of FormMail activity. It contains
3351 // the date/time, the form user's real name, their email address, and
3352 // the value of the "subject" field on the form.
3353 //
3354 // One use for the log file is for auditing: you can
3355 // check the number of successful form submissions and when they occurred.
3356 // You might use this, for example, to verify that a day's work has been
3357 // processed by your employees.
3358 //
3359 // FormMail user AlecRaenos told us how he uses the log file:
3360 // We keep "lead" counts and this log file will be a HUGE help
3361 // to us to determine:
3362 // 1) if our server is sending out all the processed forms -we
3363 // have had trouble with this and
3364 // 2) auditing how many leads we get for our business.
3365 //
3366 // You might find other uses, if so, please let us know.
3367 //
3368 // NOTE: you'll need to create the log file on your server and make
3369 // it writable by the web server software. For security reasons,
3370 // FormMail cannot do this for you.
3371 // In general, the correct permissions for your log file are:
3372 // rw-rw-rw-
3373 //
3374 // NOTE: on Windows servers, use '/' instead of '\' or double the
3375 // '\' like this:
3376 // "d:\\path\\to\\logs"
3377 // or
3378 // "d:/path/to/logs"
3379 //
3380$LOGDIR = ""; // directory for log files; empty string to
3381 // disallow log files
3382 //
3383 // ** OPTIONAL **
3384 // Set AUTORESPONDLOG to the filename on your server where auto-responding
3385 // activity is logged.
3386 //
3387 // This file is stored in the $LOGDIR directory and it *must* be outside
3388 // your web server directory. If it isn't, then someone may be able to
3389 // harvest the email addresses from your server!
3390 //
3391 // If you don't want to to keep a log of auto responding activity,
3392 // make this an empty string:
3393 // $AUTORESPONDLOG = "";
3394 //
3395 // Auto responding is a potential dangerous thing to allow from FormMail.
3396 // That's why FormMail will only do auto responding after image verification.
3397 //
3398 // However, image verification is not perfect. It is possible for a very
3399 // motivated Spammer to overcome the image verification (e.g. he could
3400 // pay people to type in the image contents for him).
3401 //
3402 // Therefore, you should keep a log of auto responding activity. This
3403 // way you can:
3404 // - confirm correct operation
3405 // - detect unusual activity
3406 // - respond to any queries from your hosting company or anyone else
3407 // accusing you of being a spam gateway
3408 //
3409 // The log file contains:
3410 // - the date/time
3411 // - the IP address from where the user is submitting
3412 // - the email address that the auto response was sent to
3413 // - the subject line that was put in the email.
3414 // - information about the activity (success, failure, etc.)
3415 //
3416 // NOTE: you'll need to create the log file on your server and make
3417 // it writable by the web server software. For security reasons,
3418 // FormMail cannot do this for you.
3419 // In general, the correct permissions for your log file are:
3420 // rw-rw-rw-
3421 //
3422$AUTORESPONDLOG = ""; // file name in $LOGDIR for the auto responder
3423 // log; empty string for no auto responder log
3424
3425 //
3426 // ** OPTIONAL **
3427 // Set CSVDIR to the directory on your server where CSV files are
3428 // stored. When the form provides a 'csvfile' value, formmail.php
3429 // expects the file to be in this directory.
3430 // Generally you want this to be outside your server's WWW directory.
3431 // For example, if your server's root (WWW) directory is:
3432 // /home/yourname/www
3433 // use a directory like
3434 // /home/yourname/csv
3435 //
3436 // If you don't want to support CSV files, make this an empty string:
3437 // $CSVDIR = "";
3438 //
3439 // NOTE: you'll need to create the CSV file on your server and make
3440 // it writable by the web server software. For security reasons,
3441 // FormMail cannot do this for you.
3442 // In general, the correct permissions for your CSV file are:
3443 // rw-rw-rw-
3444 //
3445 // NOTE: on Windows servers, use '/' instead of '\' or double the
3446 // '\' like this:
3447 // "d:\\path\\to\\csv"
3448 // or
3449 // "d:/path/to/csv"
3450 //
3451$CSVDIR = ""; // directory for csv files; empty string to
3452 // disallow csv files
3453
3454 //
3455 // ** OPTIONAL **
3456 // If you're creating a CSV database, you can choose the field
3457 // separators below.
3458 //
3459 // The defaults below will suit most purposes.
3460 //
3461$CSVSEP = ","; // comma separator between fields (columns)
3462$CSVINTSEP = ";"; // semicolon is the separator for fields (columns)
3463 // with multiple values (checkboxes, etc.)
3464$CSVQUOTE = '"'; // all fields in the CSV are quoted with this character;
3465 // default is double quote. You can change it to
3466 // single quote or leave it empty for no quotes.
3467//$CSVQUOTE = "'"; // use this if you want single quotes
3468$CSVOPEN = ""; // set to "b" to force line terminations to be
3469 // kept as $CSVLINE setting below, regardless of
3470 // operating system. Keep as empty string and
3471 // leave $CSVLINE unchanged, to get text file
3472 // terminations for your server's operating system.
3473 // (Line feed on UNIX, carriage-return line feed on Windows).
3474$CSVLINE = "\n"; // line termination for CSV files. The default is
3475 // a single line feed, which may be modified for your
3476 // server's operating system. If you want to change
3477 // this value, you *must* set $CSVOPEN = "b".
3478
3479 //
3480 // ** OPTIONAL **
3481 // Set TEMPLATEDIR to the directory on your server where template files are
3482 // stored.
3483 //
3484 // If you want to specify "good_template", "bad_template" or "HTMLTemplate"
3485 // in your forms, the templates must be found in the directory you specify
3486 // below.
3487 // This is a necessary step to prevent security problems. For example,
3488 // without this measure, an attacker might be able to gain access to
3489 // any file on your server.
3490 //
3491 // We recommend you set aside a particular directory on your
3492 // server for all your templates.
3493 //
3494 // NOTE: on Windows servers, use '/' instead of '\' or double the
3495 // '\' like this:
3496 // "d:\\path\\to\\templates"
3497 // or
3498 // "d:/path/to/templates"
3499 //
3500$TEMPLATEDIR = ""; // directory for template files; empty string
3501 // if you don't have any templates
3502
3503 //
3504 // ** OPTIONAL **
3505 // Set TEMPLATEURL to the URL where template files can be fetched.
3506 // If you set TEMPLATEDIR too, that takes precedence and TEMPLATEURL
3507 // is ignored.
3508 //
3509 // TEMPLATEURL is analogous to TEMPLATEDIR, but allows for templates
3510 // to be read from a web server. This is useful for cases where
3511 // you want the template to be generated via a PHP script, for example.
3512 //
3513 // You can use $SCHEME and $SERVER to refer to your own server.
3514 //
3515 // Note that the HTTP_USER_AGENT string is passed to any URL opened
3516 // through TEMPLATEURL with a parameter, for example:
3517 // http://blah.blah/templatedir/template.php?USER_AGENT=blahblah
3518 //
3519 // This is useful for dynamically generated pages which generate different
3520 // content depending on the user's browser.
3521 //
3522$TEMPLATEURL = ""; // default; no template URL
3523//$TEMPLATEURL = $SCHEME.$SERVER."/templatedir"; // a sample using your server
3524
3525 //
3526 // ** OPTIONAL **
3527 // Set MULTIFORMDIR to the directory on your server where multi-form
3528 // template files are stored.
3529 //
3530 // If you want to specify "next_form" in your forms, the templates must
3531 // be found in the directory you specify below.
3532 //
3533 // This is a necessary step to prevent security problems. For example,
3534 // without this measure, an attacker might be able to gain access to
3535 // any file on your server.
3536 //
3537 // We recommend you set aside a particular directory on your
3538 // server for all your multi-form templates.
3539 //
3540 // NOTE: on Windows servers, use '/' instead of '\' or double the
3541 // '\' like this:
3542 // "d:\\path\\to\\multiforms"
3543 // or
3544 // "d:/path/to/multiforms"
3545 //
3546$MULTIFORMDIR = ""; // directory for multi-form template files; empty string
3547 // if you're not using multi-forms
3548
3549 //
3550 // ** OPTIONAL **
3551 // Set MULTIFORMURL to the URL where multi-form template files can be fetched.
3552 // If you set MULTIFORMDIR too, that takes precedence and MULTIFORMURL
3553 // is ignored.
3554 //
3555 // MULTIFORMURL is analogous to MULTIFORMDIR, but allows for templates
3556 // to be read from a web server. This is useful for cases where
3557 // you want the template to be generated via a PHP script, for example.
3558 //
3559 // You can use $SCHEME and $SERVER to refer to your own server.
3560 //
3561 // Note that the HTTP_USER_AGENT string is passed to any URL opened
3562 // through MULTIFORMURL with a parameter, for example:
3563 // http://blah.blah/multiforms/page2.php?USER_AGENT=blahblah
3564 //
3565 // This is useful for dynamically generated pages which generate different
3566 // content depending on the user's browser.
3567 //
3568$MULTIFORMURL = ""; // default; no multi-forms templates URL
3569//$MULTIFORMURL = $SCHEME.$SERVER."/multiforms"; // a sample using your server
3570
3571 //
3572 // ** OPTIONAL **
3573 // When FormMail returns to a form for the user in a multi-page
3574 // form sequence, it opens a URL to read in the form. This means your
3575 // server is opening a URL to itself.
3576 //
3577 // If your form requires authentication, you need FormMail to be
3578 // able to authenticate with the server to open the URL.
3579 //
3580 // FormMail version 7.05 attempts to provide the authentication information
3581 // automatically.
3582 //
3583 // If this doesn't work on your site or you want to provide a separate
3584 // authentication for FormMail, put the value(s) here.
3585 //
3586 // $AUTHENTICATE is placed as the value of the "Authorization:" header.
3587 // For example:
3588 // Basic cnVzc2VsbHI6dGVzdA==
3589 // The second value is the Base-64 encoded user name and password
3590 // separated by ":". (The above value is: "russellr:test".)
3591 //
3592 // If this is inconvenient for you, leave $AUTHENTICATE empty and
3593 // set $AUTH_USER and $AUTH_PW as normal strings
3594 // (e.g. "russellr" and "test"). When using $AUTH_USER and $AUTH_PW
3595 // FormMail will automatically specify "Basic" authentication.
3596 //
3597 // Note: this configruation is similar to that in FMBadHandler, but
3598 // in FormMail it's only used in multi-page form processing.
3599 //
3600$AUTHENTICATE = "";
3601//$AUTHENTICATE = "Basic cnVzc2VsbHI6dGVzdA=="; // example
3602$AUTH_USER = "";
3603$AUTH_PW = "";
3604
3605 //
3606 // ** OPTIONAL **
3607 // Set $FORM_INI_FILE to the file name on your server
3608 // where you keep secret settings for your forms.
3609 //
3610 // This is how you hide email addresses, force particular conditions,
3611 // or other settings that you don't want exposed in the HTML.
3612 //
3613$FORM_INI_FILE = "";
3614//$FORM_INI_FILE = "/home/mysite/formmail.ini";
3615
3616 //
3617 // ** OPTIONAL **
3618 // Set MODULEDIR to the directory on your server where you install
3619 // FormMail compatible modules.
3620 //
3621 // The default value ('.' for current directory) is suitable if
3622 // you install modules in the same directory as formmail.php.
3623 //
3624 // Because modules may be accessible from internet browsers, you
3625 // may wish to install them in a different directory, which you
3626 // protect from unauthorized access.
3627 //
3628 // The modules we provide are generally safe from unauthorized access
3629 // but we still recommend you use a separate directory for modules
3630 // and protect it from unauthorized access using a .htaccess file or
3631 // equivalent for your web server.
3632 //
3633 // If you are reserving a directory for FormMail modules, set the
3634 // directory in this configuration setting.
3635 //
3636 // NOTE: on Windows servers, use '/' instead of '\' or double the
3637 // '\' like this:
3638 // "d:\\path\\to\\templates"
3639 // or
3640 // "d:/path/to/templates"
3641 //
3642$MODULEDIR = ".";
3643
3644 //
3645 // ** LEAVE **
3646 // Set FMCOMPUTE to the name of the "fmcompute.php" module you want
3647 // to load.
3648 //
3649 // This is a standard name, but you may want to use a different name
3650 // for temporary testing purposes.
3651 // The module is always loaded from $MODULEDIR (above).
3652 //
3653$FMCOMPUTE = "fmcompute.php";
3654
3655 //
3656 // ** LEAVE **
3657 // Set FMGEOIP to the name of the "fmgeoip.php" module you want
3658 // to load.
3659 //
3660 // This is a standard name, but you may want to use a different name
3661 // for temporary testing purposes.
3662 // The module is always loaded from $MODULEDIR (above).
3663 //
3664$FMGEOIP = "fmgeoip.php";
3665
3666 //
3667 // ** OPTIONAL **
3668 // Set LIMITED_IMPORT to false if your target database understands
3669 // escaped quotes and newlines within CSV files.
3670 //
3671 // When formmail.php is instructed to write to a CSV file, it
3672 // can strip special encodings or leave them intact.
3673 //
3674 // What you want to do depends on the final destination of your
3675 // CSV file. If you intend to import the CSV file into a database,
3676 // and the database doesn't accept these special encodings, you
3677 // must leave LIMITED_IMPORT set to true.
3678 //
3679 // Microsoft Access is one example of a database that doesn't
3680 // understand escaped quotes and newlines, so you need LIMITED_IMPORT
3681 // set to true.
3682 //
3683 // When LIMITED_IMPORT is true, the following transformations are made
3684 // on every form value before placement in the CSV file:
3685 // \\ is replaced by \
3686 // \X is replaced by X where X is any character except \
3687 // plus
3688 // control characters and multiple spaces are replaced with a single
3689 // space (the means new lines are removed too)
3690 //
3691define("LIMITED_IMPORT",true); // set to true if your database cannot
3692 // handle escaped quotes or newlines within
3693 // imported data. Microsoft Access is one
3694 // example.
3695
3696 //
3697 // ** OPTIONAL **
3698 // Set VALID_ENV to the environment variables the script is allowed to
3699 // report. No need to change.
3700 //
3701$VALID_ENV = array('HTTP_REFERER','REMOTE_HOST','REMOTE_ADDR','REMOTE_USER',
3702 'HTTP_USER_AGENT');
3703
3704 //
3705 // ** OPTIONAL **
3706 // Set FILEUPLOADS to true if you want to allow forms to upload files.
3707 // Leave at false to prevent file attachments in your emails or file
3708 // storage on the server.
3709 //
3710 // This is a security measure. Setting to false prevents attackers from
3711 // using your FormMail to send you malicious file attachments or saving
3712 // files on your server.
3713 //
3714 // The php.ini and httpd.conf files can set file_uploads to false to
3715 // disable file uploading. You cannot override a false setting in
3716 // these files.
3717 //
3718define("FILEUPLOADS",false); // set to true to allow file attachments
3719
3720 //
3721 // ** OPTIONAL **
3722 // Set MAX_FILE_UPLOAD_SIZE to the maximum size you want to allow for a file
3723 // upload. Setting this to 0 means that the HTML form or and the PHP
3724 // configuration (upload_max_filesize) on your server specify the limit.
3725 //
3726 // Specify MAX_FILE_UPLOAD_SIZE in kilobytes. For example, "4" means
3727 // 4 kilobytes, which is 4096 bytes (4 * 1024).
3728 //
3729 // You can set this in the HTML form (MAX_FILE_SIZE), but it's easily
3730 // overridden by an attacker.
3731 //
3732 // You can also set this in the php.ini or httpd.conf if you have access
3733 // to these files. If you don't have access to these files, then you can't
3734 // successfully set a *larger* size below (these files provide a hard upper
3735 // limit that a PHP script cannot override).
3736 //
3737 // But if you want a *smaller* size than specified in php.ini and httpd.conf
3738 // then you can set MAX_FILE_UPLOAD_SIZE to that smaller amount and FormMail
3739 // will enforce the smaller limit.
3740 //
3741define("MAX_FILE_UPLOAD_SIZE",0); // default of 0 means that other software
3742 // controls the maximum file upload size
3743 // (FormMail doesn't test the file size)
3744
3745 //
3746 // ** OPTIONAL **
3747 // Set $FILE_REPOSITORY to the directory path on your server where uploaded
3748 // files are to be stored. If you set this to a directory path, then
3749 // uploaded files are saved there instead of being attached to the email.
3750 //
3751 // Setting to an empty string disables the server-side storage and uploaded
3752 // files are sent by email as an attachment.
3753 //
3754$FILE_REPOSITORY = "";
3755
3756 //
3757 // ** OPTIONAL **
3758 // Set FILE_MODE to the permission mode you want for files saved
3759 // to $FILE_REPOSITORY.
3760 //
3761 // To understand the valid values, you can read about the "chmod" command
3762 // on any Linux system. This page is also helpful: http://www.php.net/chmod
3763 //
3764 // Useful values:
3765 // 0664 read-write by owner and group, read by others
3766 // 0666 read-write by everyone
3767 // 0444 read-only by everyone
3768 // 0644 read-write by owner, read by everyone else
3769 // 0 don't set the protection mode (skips setting)
3770 //
3771 // Remember that uploaded files may be owned by "apache" or "nobody".
3772 //
3773 // FILE_MODE may have no effect on Windows servers.
3774 //
3775define("FILE_MODE",0664); // always precede with 0 to specify octal!
3776
3777 //
3778 // ** OPTIONAL **
3779 // Set PUT_DATA_IN_URL to false if you want to prevent FormMail
3780 // from placing data in the URL when redirecting to bad_url.
3781 //
3782 // The default value is "true" and will work fine for forms with a small
3783 // amount of data (less than 2000 bytes, approximately.)
3784 //
3785 // However, URLs have a finite length that's dependent on the user's
3786 // browser. If you've got forms with large amounts of data, then
3787 // a redirect to bad_url will probably cause an error display to
3788 // the user, for example:
3789 // Cannot find server or DNS Error
3790 //
3791 // By setting PUT_DATA_IN_URL to false, you avoid this problem.
3792 //
3793 // In any case, error information and the data submitted in the form will
3794 // be placed in PHP session variables.
3795 //
3796 // So, if your bad_url target is written in PHP and your PHP version is
3797 // sufficient to handle sessions correctly, you'll be fine with
3798 // PUT_DATA_IN_URL set to false. (As always, test thoroughly!)
3799 //
3800 // Otherwise, you'll need to keep PUT_DATA_IN_URL set to true and your
3801 // forms will need to be small.
3802 //
3803define("PUT_DATA_IN_URL",true); // set to true to place data in the URL
3804 // for bad_url redirects
3805
3806 //
3807 // ** LEAVE **
3808 // Set DB_SEE_INPUT to true for debugging purposes only. If set to
3809 // true the script does nothing except generate a page showing you what
3810 // it will do.
3811 //
3812define("DB_SEE_INPUT",false); // set to true to just see the input values
3813
3814 //
3815 // ** LEAVE **
3816 // Set DB_SEE_INI to true for debugging purposes only. If set to
3817 // true the script does nothing except generate a page showing you what
3818 // it found in the $FORM_INI_FILE file.
3819 //
3820define("DB_SEE_INI",false); // set to true to just see the ini file
3821
3822 //
3823 // ** OPTIONAL **
3824 // Set MAXSTRING to limit the maximum length of any value accepted
3825 // from the form. Increase this if you have TEXTAREAs in your forms
3826 // and you want users to be able to enter lots of data.
3827 // This value has no effect on file upload size.
3828 //
3829define("MAXSTRING",1024); // maximum string length for a value
3830
3831 //
3832 // ** OPTIONAL **
3833 // Set $bShowMesgNumbers to true to set message numbers on.
3834 // if message numbers are shown then every message from FormMail
3835 // as [Mnnn] displayed with it, where nnn is the message number.
3836 // The message number is useful if:
3837 // - you use a language other than English and you need to contact
3838 // us (who only speak English) to tell us the exact messages being
3839 // issued by FormMail,
3840 // or
3841 // - you prefer to know the precise error message being produced
3842 // regardless of the text (for example, for searching the FormMail
3843 // source for the occurrence of the message)
3844 //
3845 // Initially, FormMail always showed message numbers. However, several
3846 // customers found this annoying and, so, we've made it optional with
3847 // the default being "off".
3848 //
3849$bShowMesgNumbers = false;
3850
3851 //
3852 // ** OPTIONAL **
3853 // Set FILTERS to the filter programs you want to support.
3854 // A filter program is used to process the data before sending in email.
3855 // For example, an encryption program can be used to encrypt the mail.
3856 // Note that formmail.php changes to the directory of the filter program
3857 // before running the filter, so file name arguments are relative
3858 // to that directory.
3859 //
3860 // The format for each filter program is:
3861 // "name"=>"program path [program options]"
3862 // Here's an example:
3863 // $FILTERS = array("encode"=>"$REAL_DOCUMENT_ROOT/cgi-bin/fmencoder");
3864 //
3865 // This says that when the form specifies a 'filter' value of
3866 // "encode", run the email through this program:
3867 // $REAL_DOCUMENT_ROOT/cgi-bin/fmencoder
3868 //
3869 // You can use the special variable $REAL_DOCUMENT_ROOT to refer
3870 // to the top of your web server directory.
3871 // The program can also be outside of the web server directory, e.g.:
3872 // /home/yourname/bin/fmencoder
3873 //
3874 // The default value below is ready for use with FormMailEncoder.
3875 // FormMailEncoder allows your form results to be strongly encrypted
3876 // before being mailed to you.
3877 //
3878 // Use this to collect credit card payments from your customers or
3879 // just to keep their details private.
3880 //
3881 // You need our FormMailDecoder product to decrypt these messages.
3882 // You can purchase FormMailDecoder and FormMailEncoder
3883 // from us at http://www.tectite.com.
3884 //
3885 // The settings below have no effect unless your HTML forms request
3886 // their use. So, you can leave them set to the values below.
3887 //
3888 // Please note that on Windows servers, you can use '/' to separate
3889 // directory names. But, if you use '\', then you must double it
3890 // like this:
3891 // "encode"=>"d:\\websites\\yoursite\\fmencoder -kpubkey.txt"
3892 // or
3893 // "encode"=>"d:/websites/yoursite/fmencoder -kpubkey.txt"
3894 //
3895 //
3896 // Note: the "null" filter does nothing to the message.
3897 // You can use the null filter for testing your form prior to changing
3898 // to a real filter.
3899 // You can also use the null filter to attach the form submission to the
3900 // email instead of having it in the body of the email (use the
3901 // filter_options "Attach=filename" feature).
3902 //
3903$FILTERS = array("encode"=>"$REAL_DOCUMENT_ROOT/cgi-bin/fmencoder -kpubkey.txt",
3904 "null"=>"null");
3905
3906 //
3907 // ** OPTIONAL **
3908 // Set SOCKET_FILTERS to filter programs you want to access via HTTP
3909 // or HTTPS connections.
3910 //
3911 // Server Restrictions
3912 // ~~~~~~~~~~~~~~~~~~~
3913 //
3914 // Some server setups prevent the execution of external programs.
3915 // Provided you can execute cgi-bin programs from a web browser (i.e.
3916 // an HTTP connection), we've provided a workaround for this situation.
3917 // FormMail can execute your cgi-bin filter program using an HTTP (or,
3918 // if your PHP is configured correctly, an HTTPS) connection.
3919 //
3920 // Note: this is supported by fmencoder version 1.4 and above only.
3921 //
3922 // To execute fmencoder via HTTP, do this:
3923 // 1. Change the "site" value for "httpencode" to your site's web
3924 // address.
3925 // 2. Upload your public key to the file "pubkey.txt" in your cgi-bin
3926 // directory (or change the "file" setting in the "params" value).
3927 // 3. Add this hidden field to your HTML form:
3928 // <input type="hidden" name="filter" value="httpencode" />
3929 //
3930 // This is still secure because the information never leaves your
3931 // server in clear text form. However, if you need to execute fmencoder
3932 // on another server (i.e. a server different from the one that has
3933 // your FormMail script), you need to use the "sslencode" filter
3934 // instead of the "httpencode" filter. Contact us for assistance if
3935 // you require this.
3936 //
3937$SOCKET_FILTERS = array(
3938 "httpencode"=>array("site"=>"YourSiteHere",
3939 "port"=>80,
3940 "path"=>"/cgi-bin/fmencoder",
3941 "params"=>array(array("name"=>"key",
3942 "file"=>"$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt"))),
3943 "sslencode"=>array("site"=>"ssl://YourSecureSiteHere",
3944 "port"=>443,
3945 "path"=>"/cgi-bin/fmencoder",
3946 "params"=>array(array("name"=>"key",
3947 "file"=>"$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt"))),
3948 );
3949
3950 //
3951 // ** OPTIONAL **
3952 // Set FILTER_ATTRIBS to describe the attributes of your filters.
3953 //
3954 // Supported attributes are:
3955 // Strips the filter returns a block of data, stripped of any
3956 // formatting (e.g. any HTML is removed)
3957 // MIME the MIME type that the filter outputs:
3958 // MIME=text/plain
3959 //
3960$FILTER_ATTRIBS = array("encode"=>"Strips,MIME=text/plain",
3961 "httpencode"=>"Strips,MIME=text/plain",
3962 "sslencode"=>"Strips,MIME=text/plain",);
3963
3964 //
3965 // ** OPTIONAL **
3966 // Set CHECK_FOR_NEW_VERSION to false if you don't want FormMail
3967 // to check for a new version and report it to you.
3968 //
3969 // The check is made once every 3 days or if your server is rebooted (or
3970 // its system directory for temporary files is cleaned).
3971 //
3972 // If a new version is found, then this is reported to you via an Alert.
3973 //
3974 // FormMail attempts to create a unique file in your server's temporary
3975 // directory (e.g. /tmp on Linix) to record when it last performed a version
3976 // check. The unique file name is derived from your $TARGET_EMAIL setting.
3977 //
3978 // If you provide a value for SCRATCH_PAD (see below), then that directory
3979 // is used instead of /tmp. If your web server software cannot write
3980 // to your server's /tmp directory, set SCRATCH_PAD if you want version
3981 // checks.
3982 //
3983 // CHECK_DAYS specifies the number of days between checks (if your server
3984 // is rebooted, a check may be made regardless).
3985 //
3986define("CHECK_FOR_NEW_VERSION",true);
3987define("CHECK_DAYS",30);
3988
3989 //
3990 // ** OPTIONAL **
3991 // Set SCRATCH_PAD to a directory into which FormMail can create files.
3992 // The SCRATCH_PAD directory must be writable by your web server software.
3993 // On Linux, the following mode should work:
3994 // rwxrwxrwx
3995 //
3996 // If you set it, the SCRATCH_PAD directory is used for CHECK_FOR_NEW_VERSION
3997 // processing and any other time FormMail needs to create a temporary
3998 // file. If you don't set it, then FormMail uses your system's temporary
3999 // directory (e.g. /tmp on Linux).
4000 //
4001 // We recommend you create the directory *above* your web server document
4002 // directory, if possible. For example, if your web pages are served
4003 // from:
4004 // /home/your-site/public_html
4005 // create a directory called:
4006 // /home/your-site/fmscratchpad
4007 //
4008 // This more secure as no browser will be able to view the scratch pad
4009 // directory.
4010 //
4011 // Do not specify a system directory where other FormMail installations
4012 // may write to.
4013 //
4014 // We recommend specifying the full path (not a relative path) in SCRATCH_PAD.
4015 //
4016 // NOTE: on Windows servers, use '/' instead of '\' or double the
4017 // '\' like this:
4018 // "d:\\path\\to\\scratchpad"
4019 // or
4020 // "d:/path/to/scratchpad"
4021 //
4022$SCRATCH_PAD = "";
4023
4024 //
4025 // ** OPTIONAL **
4026 // If you need to use an outgoing mail server other than the one configured
4027 // directly for PHP, *and* your PHP installation has PEAR support,
4028 // you can configure FormMail to use PEAR's "Mail" object to send
4029 // mail.
4030 //
4031 // To do this, you need to set $PEAR_SMTP_HOST to the name of the
4032 // outgoing mail server. The default port for SMTP is 25, but you
4033 // can specify a different one if required.
4034 // If you don't need authentication, leave $PEAR_SMTP_USER blank,
4035 // otherwise, set it to the user name and set $PEAR_SMTP_PWD to the
4036 // required password. Note that servers frequently require a complete
4037 // email address for $PEAR_SMTP_USER (e.g. "russellr@rootsoftware.com"
4038 // instead of just "russellr").
4039 //
4040 // When using PEAR, emails seem to require a sender (a 'From' address).
4041 // Therefore, you may need to set "$FROM_USER" (above) to get alert messages
4042 // to work.
4043 //
4044 // Note that with PEAR mailing enabled, the SendMailFOption "mail_options"
4045 // setting is ignored (and so is SENDMAIL_F_OPTION).
4046 //
4047 // Test your PEAR settings with the "testalert" feature:
4048 // http://yoursite.com/formmail.php?testalert=1
4049 //
4050$PEAR_SMTP_HOST = "";
4051$PEAR_SMTP_PORT = 25;
4052$PEAR_SMTP_USER = "";
4053$PEAR_SMTP_PWD = "";
4054
4055 //
4056 // ** OPTIONAL **
4057 // Set ALERT_ON_USER_ERROR to false if you don't want FormMail
4058 // to send you an alert when a user error (e.g. missing field) occurs
4059 // on your forms.
4060 // We recommend you leave this "true" while you debug your forms and
4061 // either leave it that way or set it to "false" for your production
4062 // environment.
4063 //
4064define("ALERT_ON_USER_ERROR",true);
4065
4066 //
4067 // ** OPTIONAL **
4068 // Set ENABLE_ATTACK_DETECTION to false if you don't want FormMail
4069 // to try to detect an attack designed to abuse your server.
4070 //
4071 // The only reason you may want to set this to false is if you're
4072 // testing FormMail's attack detection features.
4073 //
4074 // FormMail has never been vulnerable to any of the attacks that it
4075 // can detect. The *purpose* of attack detection is merely to prevent
4076 // it from sending you an annoying alert whenever an attack happens.
4077 //
4078 // If you're using our FormMail, the only effect of this attack is one
4079 // or more annoying alert messages (your server is safe).
4080 //
4081define("ENABLE_ATTACK_DETECTION",true);
4082
4083 //
4084 // ** OPTIONAL **
4085 // Set ALERT_ON_ATTACK_DETECTION to true if you want FormMail
4086 // to send you an alert when it detects an attack designed to
4087 // abuse your server.
4088 // If you set this to true, you may get lots of alert messages
4089 // each time an attack occurs.
4090 //
4091define("ALERT_ON_ATTACK_DETECTION",false);
4092
4093 //
4094 // ** LEAVE **
4095 // Set ATTACK_DETECTION_MIME to false if you don't want FormMail's
4096 // attack detection to check for the MIME attack.
4097 // The MIME attack is where the recipient's address is carefully
4098 // crafted to try to fool FormMail into sending an with a virus
4099 // or other malware file attached.
4100 //
4101define("ATTACK_DETECTION_MIME",true);
4102
4103 //
4104 // ** OPTIONAL **
4105 // Set $ATTACK_DETECTION_DUPS to the list of fields on your forms
4106 // that should *not* have duplicate values.
4107 //
4108 // One annoying attack on HTML forms scripts is to submit an email address in
4109 // every field, with the aim of getting the script to send email to
4110 // someone via your server.
4111 //
4112 // If you use one form on your server, just list some or all of the fields
4113 // that should never contain duplicate data. For example, a person's
4114 // name is never the same as their address or their email address.
4115 //
4116 // If you use more than one form, you can list fields from each of
4117 // them or just use a common set.
4118 //
4119 // FormMail ignores empty or missing fields when performing this particular
4120 // abuse detection. This means listing field names you don't actually
4121 // have on a form is OK.
4122 //
4123 // If you don't want FormMail to perform this particular attack detection,
4124 // set it to an empty array like this:
4125 // $ATTACK_DETECTION_DUPS = array();
4126 //
4127 // Following is a list of common fields you might want FormMail to check
4128 // for duplicate data. Use this unless you think it's valid for a user to put
4129 // the same data in *any* of these fields. If your fields have different
4130 // names, change the names.
4131 //
4132 // Do not list checkbox, radio button, or select fields that have
4133 // simple values such as "yes", "no", "0", "1". Only list fields
4134 // that will have long and unique values.
4135 //
4136$ATTACK_DETECTION_DUPS = array("realname","address1","address2","country","zip",
4137 "phone","postcode","state","email");
4138
4139 //
4140 // ** LEAVE **
4141 // Set ATTACK_DETECTION_SPECIALS to false if you don't want FormMail's
4142 // attack detection to check for the "email address in a special field"
4143 // attack.
4144 //
4145define("ATTACK_DETECTION_SPECIALS",true);
4146
4147 //
4148 // ** OPTIONAL **
4149 // Set $GEOIP_LIC to the license key for your GeoIP account.
4150 // GeoIP provides geographical positioning and other information
4151 // about an IP address. You can use this for helping to detect
4152 // credit card fraud, for example, by locating the form submitter's
4153 // IP address and comparing it with their stated address (For example,
4154 // "John Smith" submits your form and claims to be in Sydney
4155 // Australia. But the GeoIP information indicates his actual IP address
4156 // is in Pakistan!)
4157 // For more information about GeoIP, go to:
4158 // http://www.tectite.com/geoip.php
4159 //
4160$GEOIP_LIC = ""; // default - no GeoIP
4161
4162 //
4163 // ** OPTIONAL **
4164 // Set ZERO_IS_EMPTY to false if you don't want a field containing
4165 // exactly "0" (without the quotes) to be treated as empty.
4166 //
4167 // The default behaviour of PHP is to treat a field containing "0" as empty
4168 // and this behaviour is what FormMail mimics by default.
4169 //
4170 // In many cases this is what you would want for a web form.
4171 //
4172 // By setting ZERO_IS_EMPTY to false, then a field must be completely
4173 // empty to be treated as such.
4174 //
4175 // This setting affects "required" testing, "derived_fields" + operator,
4176 // "conditions" testing, and template filling.
4177 //
4178 // References:
4179 // http://au2.php.net/empty
4180 // http://aspn.activestate.com/ASPN/docs/PHP/migration4.empty.html
4181 //
4182 // If you're upgrading FormMail through the Upgrade Wizard, the setting
4183 // will be set to "true" to replicate previous behaviour. New FormMail
4184 // downloads get the setting as "false".
4185 //
4186define("ZERO_IS_EMPTY",false);
4187
4188 //
4189 // ** OPTIONAL **
4190 // Set SESSION_NAME to a non-empty string to get a unique PHP session for
4191 // your FormMail processing. You only need to do this if your site
4192 // is a PHP-based site that uses sessions.
4193 //
4194 // FormMail attaches to or creates a PHP session so it can pass error
4195 // information to bad_url. On succcessful completion, and if you're not
4196 // using good_url, FormMail destroys the session. If you use the default
4197 // PHP session name on your site and within FormMail, this will cause any
4198 // session information from your site to be discarded.
4199 //
4200 // In summary, you'll only have a problem with sessions, and need to
4201 // set $SESSION_NAME if *all* the following statements are true:
4202 // 1. Your website uses PHP sessions.
4203 // 2. Your website's PHP session name is the default for PHP.
4204 // 3. You do not specify "good_url" in your HTML form
4205 //
4206 // By specifying a unique name here, you avoid this problem. You should set
4207 // the same name in FMBadHandler too, if you're using that script.
4208 // Also, VerifyImg.php if you're using that.
4209 //
4210$SESSION_NAME = "";
4211
4212 //
4213 // ** OPTIONAL **
4214 // Set $HOOK_DIR to a directory path on your server where you store
4215 // include files for the FormMail Hook System.
4216 //
4217 // Note that this setting has to be a directory (folder) path, not a URL.
4218 //
4219 // If set to an empty string (the default), the Hook System is disabled.
4220 //
4221$HOOK_DIR = "";
4222
4223/* UPGRADE CONTROL
4224**
4225** FILTER_ATTRIBS:lt:4.00:no_keep:The FILTER_ATTRIBS configuration has
4226** been modified to include new information about the standard filters.:
4227**
4228** SET_REAL_DOCUMENT_ROOT:gt:4.07:copy_from=REAL_DOCUMENT_ROOT:The
4229** REAL_DOCUMENT_ROOT configuration has been renamed to SET_REAL_DOCUMENT_ROOT.:
4230**
4231** EMAIL_NAME:lt:6.01:no_keep:The EMAIL_NAME configuration has
4232** been modified to match hyphens ('-') in email addresses.:
4233**
4234** ZERO_IS_EMPTY:le:6.01:set_to=true:ZERO_IS_EMPTY has been
4235** set to a value that duplicates previous behaviour.:
4236**
4237** END OF CONTROL
4238*/
4239
4240/*****************************************************************************/
4241/* END OF CONFIGURATION (do not alter this line in any way!!!) */
4242/*****************************************************************************/
4243 //
4244 // Hook system: before initialization (but after configuration)
4245 //
4246if ($HOOK_DIR !== "")
4247 @include("$HOOK_DIR/fmhookpreinit.inc");
4248
4249if (!empty($SESSION_NAME))
4250 session_name($SESSION_NAME);
4251
4252session_start();
4253
4254function ZapSession()
4255{
4256 session_destroy();
4257}
4258
4259if ($bUseOldVars)
4260 $aSessionVars = &$HTTP_SESSION_VARS;
4261else
4262 $aSessionVars = &$_SESSION;
4263
4264$aSessionVars["FormError"] = NULL;
4265unset($aSessionVars["FormError"]); // start with no error
4266$aSessionVars["FormErrorInfo"] = NULL;
4267unset($aSessionVars["FormErrorInfo"]); // start with no error
4268$aSessionVars["FormErrorCode"] = NULL;
4269unset($aSessionVars["FormErrorCode"]); // start with no error
4270$aSessionVars["FormErrorItems"] = NULL;
4271unset($aSessionVars["FormErrorItems"]); // start with no error
4272$aSessionVars["FormData"] = NULL;
4273unset($aSessionVars["FormData"]); // start with no data
4274$aSessionVars["FormIsUserError"] = NULL;
4275unset($aSessionVars["FormIsUserError"]); // start with no data
4276$aSessionVars["FormAlerted"] = NULL;
4277unset($aSessionVars["FormAlerted"]); // start with no data
4278
4279//
4280// Note that HTTP_REFERER is easily spoofed, so there's no point in
4281// using it for security.
4282//
4283
4284 //
4285 // SPECIAL_FIELDS is the list of fields that formmail.php looks for to
4286 // control its operation
4287 //
4288$SPECIAL_FIELDS = array(
4289 "email", // email address of the person who filled in the form
4290 "realname", // the real name of the person who filled in the form
4291 "recipients", // comma-separated list of email addresses to which we'll send the results
4292 "cc", // comma-separated list of email addresses to which we'll CC the results
4293 "bcc", // comma-separated list of email addresses to which we'll BCC the results
4294 "required", // comma-separated list of fields that must be found in the input
4295 "conditions", // complex condition tests
4296 "fmcompute", // computations
4297 "fmmodules", // list of modules required
4298 "mail_options", // comma-separated list of options
4299 "good_url", // URL to go to on success
4300 "good_template",// template file to display on success
4301 "bad_url", // URL to go to on error
4302 "bad_template", // template file to display on error
4303 "template_list_sep", // separator when expanding lists in templates
4304 "this_form", // the URL of the form (can be used by bad_url)
4305 "subject", // subject for the email
4306 "env_report", // comma-separated list of environment variables to report
4307 "filter", // a supported filter to use
4308 "filter_options",// options for using the filter
4309 "filter_fields",// list of fields to filter (default is to filter all fields)
4310 "logfile", // log file to write to
4311 "csvfile", // file to write CSV records to
4312 "csvcolumns", // columns to save in the csvfile
4313 "crm_url", // URL for sending data to the CRM; note that the
4314 // value must have a valid prefix specified in TARGET_URLS
4315 "crm_spec", // CRM specification (field mapping)
4316 "crm_options", // comma-separated list of options to control CRM processing
4317 "derive_fields", // a list of fields to derive from other fields
4318 "file_names", // specifies names for files being uploaded
4319 "autorespond", // specification for auto-responding
4320 "arverify", // verification field to allow auto-responding
4321 "imgverify", // verification field to allow submission
4322 "multi_start", // set this field on the first page of a multi-page form sequence
4323 "multi_keep", // set this field on the pages of a multi-page form sequence
4324 // to the list of fields that should be kept when moving
4325 // forward after going backwards
4326 "next_form", // next form name or empty for last form
4327 "multi_go_back",// this field should be set when the user clicks the
4328 // back button or link in a multi-page form sequence
4329 "alert_to"); // email address to send alerts (errors) to
4330
4331 //
4332 // $SPECIAL_MULTI is the list of fields from $SPECIAL_FIELDS that can
4333 // have multiple values, for example:
4334 // name="conditions1"
4335 // name="conditions2"
4336 //
4337$SPECIAL_MULTI = array(
4338 "conditions",
4339 "fmcompute",
4340 );
4341
4342 //
4343 // $SPECIAL_NOSTRIP is the list of fields from $SPECIAL_FIELDS that
4344 // should not be stripped (other than for magic_quotes_gpc reasons).
4345 //
4346$SPECIAL_NOSTRIP = array(
4347 "conditions",
4348 "fmcompute",
4349 );
4350
4351 //
4352 // VALID_MAIL_OPTIONS lists the valid mail_options words
4353 //
4354$VALID_MAIL_OPTIONS = array(
4355 "AlwaysList"=>true,
4356 "CharSet"=>true,
4357 "DupHeader"=>true,
4358 "Exclude"=>true,
4359 "FromAddr"=>true,
4360 "HTMLTemplate"=>true,
4361 "KeepLines"=>true,
4362 "NoEmpty"=>true,
4363 "NoPlain"=>true,
4364 "PlainTemplate"=>true,
4365 "SendMailFOption"=>true,
4366 "StartLine"=>true,
4367 "TemplateMissing"=>true,
4368 );
4369
4370 //
4371 // VALID_CRM_OPTIONS lists the valid crm_options words
4372 //
4373$VALID_CRM_OPTIONS = array(
4374 "ErrorOnFail"=>true,
4375 );
4376
4377 //
4378 // VALID_AR_OPTIONS lists the valid autorespond words
4379 //
4380$VALID_AR_OPTIONS = array(
4381 "Subject"=>true,
4382 "HTMLTemplate"=>true,
4383 "PlainTemplate"=>true,
4384 "TemplateMissing"=>true,
4385 );
4386
4387 //
4388 // VALID_FILTER_OPTIONS lists the valid filter_options words
4389 //
4390$VALID_FILTER_OPTIONS = array(
4391 "Attach"=>true,
4392 "KeepInLine"=>true,
4393 );
4394
4395 //
4396 // SPECIAL_VALUES is set to the value of the fields we've found
4397 // usage: $SPECIAL_VALUES["email"] is the value of the email field
4398 //
4399$SPECIAL_VALUES = array();
4400 //
4401 // Array of mail options; set by the function 'ProcessMailOptions'
4402 //
4403$MAIL_OPTS = array();
4404 //
4405 // Array of crm options; set by the function 'ProcessCRMOptions'
4406 //
4407$CRM_OPTS = array();
4408 //
4409 // Array of autorespond options; set by the function 'ProcessAROptions'
4410 //
4411$AR_OPTS = array();
4412 //
4413 // Array of filter options; set by the function 'ProcessFilterOptions'
4414 //
4415$FILTER_OPTS = array();
4416
4417 //
4418 // initialise $SPECIAL_VALUES so that we don't fail on using unset values
4419 //
4420foreach ($SPECIAL_FIELDS as $sFieldName)
4421 $SPECIAL_VALUES[$sFieldName] = "";
4422
4423 //
4424 // Special defaults for some fields....
4425 //
4426$SPECIAL_VALUES['template_list_sep'] = ",";
4427
4428 //
4429 // FORMATTED_INPUT contains the input variables formatted nicely
4430 // This is used for error reporting and debugging only.
4431 //
4432$FORMATTED_INPUT = array();
4433
4434 //
4435 // $FILTER_ATTRIBS_LOOKUP is the parsed $FILTER_ATTRIBS array
4436 //
4437$FILTER_ATTRIBS_LOOKUP = array();
4438
4439 //
4440 // $EMAIL_ADDRS is the array of email addresses from the $FORM_INI_FILE
4441 //
4442$EMAIL_ADDRS = array();
4443
4444 //
4445 // Access the www.tectite.com website to get the current version.
4446 //
4447function CheckVersion()
4448{
4449 global $FM_VERS;
4450
4451 $fp = fopen("http://www.tectite.com/fmversion.txt","r");
4452 if ($fp !== false)
4453 {
4454 //
4455 // version file looks like this:
4456 // Version=versionumber
4457 // Message=a message to send in the alert
4458 //
4459 $s_version = "";
4460 $s_message = "";
4461 $s_line = "";
4462 $b_in_mesg = false;
4463 while (!feof($fp))
4464 {
4465 $s_line = fgets($fp,1024);
4466 if ($b_in_mesg)
4467 $s_message .= $s_line;
4468 else
4469 {
4470 $s_prefix = substr($s_line,0,8);
4471 if ($s_prefix == "Message=")
4472 {
4473 $s_message .= substr($s_line,8);
4474 $b_in_mesg = true;
4475 }
4476 elseif ($s_prefix == "Version=")
4477 $s_version = substr($s_line,8);
4478 }
4479 }
4480 fclose($fp);
4481 $s_version = str_replace("\r","",$s_version);
4482 $s_version = str_replace("\n","",$s_version);
4483 $s_stop_mesg = GetMessage(MSG_END_VERS_CHK);
4484 if ((float) $s_version > (float) $FM_VERS)
4485 SendAlert(GetMessage(MSG_VERS_CHK,array(
4486 "TECTITE"=>"www.tectite.com",
4487 "FM_VERS"=>"$FM_VERS",
4488 "NEWVERS"=>$s_version,
4489 ))."\n$s_message\n$s_stop_mesg",true,true);
4490 }
4491}
4492
4493 //
4494 // Check for new FormMail version
4495 //
4496function Check4Update($s_chk_file,$s_id = "")
4497{
4498 global $lNow,$php_errormsg;
4499
4500@ $l_last_chk = filemtime($s_chk_file);
4501 if ($l_last_chk === false || $lNow - $l_last_chk >= (CHECK_DAYS*24*60*60))
4502 {
4503 CheckVersion();
4504 //
4505 // update the check file's time stamp
4506 //
4507 @ $fp = fopen($s_chk_file,"w");
4508 if ($fp !== false)
4509 {
4510 fwrite($fp,"FormMail version check ".
4511 (empty($s_id) ? "" : "for identifier '$s_id' ").
4512 "at ".date("H:i:s d-M-Y",$lNow)."\n");
4513 fclose($fp);
4514 }
4515 else
4516 SendAlert(GetMessage(MSG_CHK_FILE_ERROR,array("FILE"=>$s_chk_file,
4517 "ERROR"=>CheckString($php_errormsg))));
4518 }
4519}
4520
4521 //
4522 // Perform various processing at the end of the script's execution.
4523 //
4524function OnExit()
4525{
4526 global $TARGET_EMAIL,$CHECK_FILE;
4527
4528 //
4529 // Check the www.tectite.com website for a new version, but only
4530 // do this check once every 3 days (or on server reboot).
4531 //
4532 if (CHECK_FOR_NEW_VERSION)
4533 {
4534 global $SERVER;
4535
4536 if (isset($TARGET_EMAIL[0]))
4537 {
4538 //
4539 // use the first few characters of the MD5 of first email
4540 // address pattern from $TARGET_EMAIL to get a unique file
4541 // for the server
4542 //
4543 $s_id = "";
4544 if (isset($SERVER) && !empty($SERVER))
4545 $s_id = $SERVER;
4546 $s_dir = GetTempDir();
4547 $s_md5 = md5($TARGET_EMAIL[0]);
4548 $s_uniq = substr($s_md5,0,6);
4549 $s_chk_file = "fm"."$s_uniq".".txt";
4550 Check4Update($s_dir."/".$s_chk_file,$s_id);
4551 }
4552 }
4553}
4554
4555register_shutdown_function('OnExit');
4556
4557 //
4558 // Return the array with each string urlencode'd.
4559 //
4560function URLEncodeArray($a_array)
4561{
4562 foreach ($a_array as $m_key=>$s_str)
4563 {
4564 //
4565 // only encode the value after the '='
4566 //
4567 if (($i_pos = strpos($s_str,'=')) !== false)
4568 $a_array[$m_key] = substr($s_str,0,$i_pos+1).
4569 urlencode(substr($s_str,$i_pos+1));
4570 else
4571 $a_array[$m_key] = urlencode($s_str);
4572 }
4573 return ($a_array);
4574}
4575
4576 //
4577 // Add a parameter or list of parameters to a URL.
4578 //
4579function AddURLParams($s_url,$m_params,$b_encode = true)
4580{
4581 if (!empty($m_params))
4582 {
4583 if (!is_array($m_params))
4584 $m_params = array($m_params);
4585 if (strpos($s_url,'?') === false)
4586 $s_url .= '?';
4587 else
4588 $s_url .= '&';
4589 $s_url .= implode('&',($b_encode) ? URLEncodeArray($m_params) : $m_params);
4590 }
4591 return ($s_url);
4592}
4593
4594 //
4595 // Recursively trim an array of strings (non string values are converted
4596 // to a string first).
4597 //
4598function TrimArray($a_list)
4599{
4600 foreach ($a_list as $m_key=>$m_item)
4601 if (is_array($m_item))
4602 $a_list[$m_key] = TrimArray($m_item);
4603 elseif (is_scalar($m_item))
4604 $a_list[$m_key] = trim("$m_item");
4605 else
4606 $a_list[$m_key] = "";
4607 return ($a_list);
4608}
4609
4610 //
4611 // Parse a derivation specification and return an array of
4612 // field names and operators.
4613 //
4614function ParseDerivation($a_form_data,$s_fld_spec,$s_name,&$a_errors)
4615{
4616 $a_deriv = array();
4617 while (($i_len = strlen($s_fld_spec)) > 0)
4618 {
4619 //
4620 // we support the following operators:
4621 // + concatenate with a single space between, but skip the space
4622 // if the next field is empty
4623 // * concatenate with a single space between
4624 // . concatenate with no space between
4625 //
4626 $i_span = strcspn($s_fld_spec,'+*.');
4627 if ($i_span == 0)
4628 {
4629 $a_errors[] = $s_name;
4630 return (false);
4631 }
4632 $a_deriv[] = trim(substr($s_fld_spec,0,$i_span));
4633 if ($i_span < $i_len)
4634 {
4635 $a_deriv[] = substr($s_fld_spec,$i_span,1);
4636 $s_fld_spec = substr($s_fld_spec,$i_span+1);
4637 }
4638 else
4639 $s_fld_spec = "";
4640 }
4641 return ($a_deriv);
4642}
4643
4644 //
4645 // Test if a character is an alphabetic.
4646 //
4647function IsAlpha($ch)
4648{
4649 return (strpos("abcdefghijklmnopqrstuvwxyz",strtolower($ch)) !== false);
4650}
4651
4652 //
4653 // Test if a character is a digit.
4654 //
4655function IsNumeric($ch)
4656{
4657 return (strpos("0123456789",$ch) !== false);
4658}
4659
4660 //
4661 // Test if a character is an alphanumeric
4662 //
4663function IsAlnum($ch)
4664{
4665 return (IsAlpha($ch) || IsNumeric($ch));
4666}
4667
4668 //
4669 // Return an array of tokens extracted from the given string.
4670 // A token is:
4671 // - a word (begins with alpha or _, and is followed by any number
4672 // of alphanumerics or _ chars)
4673 // - a number (any number of consecutive digits with up to one period)
4674 // - a string enclosed in specified quotes (this can be disabled)
4675 // - any punctuation character
4676 //
4677 // Anything not matching the above is silently ignored!
4678 //
4679function GetTokens($s_str,$s_quotes = "'\"")
4680{
4681 $b_allow_strings = ($s_quotes !== "") ? true : false;
4682 $ii = 0;
4683 $i_len = strlen($s_str);
4684 $a_toks = array();
4685
4686 while ($ii < $i_len)
4687 {
4688 switch ($ch = $s_str{$ii})
4689 {
4690 case " ":
4691 case "\t":
4692 case "\n":
4693 case "\r":
4694 $ii++;
4695 continue;
4696 }
4697 //
4698 // start of a token
4699 //
4700 $i_start = $ii;
4701 if ($ch == "_" || IsAlpha($ch))
4702 {
4703 //
4704 // a word
4705 //
4706 $i_count = 1;
4707 while (++$ii < $i_len &&
4708 ($s_str{$ii} == "_" || IsAlnum($s_str{$ii})))
4709 ++$i_count;
4710 $a_toks[] = substr($s_str,$i_start,$i_count);
4711 }
4712 elseif (($ch == "." && $ii < ($i_len-1) && IsNumeric($s_str{$ii+1}))||
4713 IsNumeric($ch))
4714 {
4715 //
4716 // a number
4717 //
4718 $b_had_dot = ($ch == ".");
4719 $i_count = 1;
4720 while (++$ii < $i_len)
4721 {
4722 if (IsNumeric($s_str{$ii}))
4723 ++$i_count;
4724 elseif ($s_str{$ii} == "." && !$b_had_dot)
4725 {
4726 ++$i_count;
4727 $b_had_dot = true;
4728 }
4729 else
4730 break;
4731 }
4732 $a_toks[] = substr($s_str,$i_start,$i_count);
4733 }
4734 elseif ($b_allow_strings && strpos($s_quotes,$ch) !== false)
4735 {
4736 $c_quote = $ch;
4737 //
4738 // a quoted string
4739 //
4740 while (++$ii < $i_len)
4741 {
4742 if ($s_str{$ii} == $c_quote)
4743 {
4744 ++$ii; // include the terminating quote
4745 break;
4746 }
4747 }
4748 $a_toks[] = substr($s_str,$i_start,$ii-$i_start);
4749 }
4750 else
4751 {
4752 $s_punct = "~!@#$%^&*()-+={}[]|:;<>,.?/`\\";
4753 if (!$b_allow_strings)
4754 $s_punct .= "'\"";
4755 if (strpos($s_punct,$ch) !== false)
4756 $a_toks[] = $ch;
4757 ++$ii;
4758 }
4759 }
4760 return ($a_toks);
4761}
4762
4763 //
4764 // Return the value from a derive_fields specification.
4765 // Specifications are in this format:
4766 // %info%
4767 // where info is a predefined word or a literal in quotes
4768 // (e.g. 'the time is ')
4769 //
4770function ValueSpec($s_spec,$a_form_data,&$a_errors)
4771{
4772 global $lNow;
4773
4774 $s_value = "";
4775 switch (trim($s_spec))
4776 {
4777 case 'date': // "standard" date format: DD-MMM-YYYY
4778 $s_value = date('d-M-Y',$lNow);
4779 break;
4780 case 'time': // "standard" time format: HH:MM:SS
4781 $s_value = date('H:i:s',$lNow);
4782 break;
4783 case 'ampm': // am or pm
4784 $s_value = date('a',$lNow);
4785 break;
4786 case 'AMPM': // AM or PM
4787 $s_value = date('A',$lNow);
4788 break;
4789 case 'dom0': // day of month with possible leading zero
4790 $s_value = date('d',$lNow);
4791 break;
4792 case 'dom': // day of month with no leading zero
4793 $s_value = date('j',$lNow);
4794 break;
4795 case 'day': // day name (abbreviated)
4796 $s_value = date('D',$lNow);
4797 break;
4798 case 'dayname': // day name (full)
4799 $s_value = date('l',$lNow);
4800 break;
4801 case 'daysuffix': // day number suffix for English (st for 1st, nd for 2nd, etc.)
4802 $s_value = date('S',$lNow);
4803 break;
4804 case 'moy0': // month of year with possible leading zero
4805 $s_value = date('m',$lNow);
4806 break;
4807 case 'moy': // month of year with no leading zero
4808 $s_value = date('n',$lNow);
4809 break;
4810 case 'month': // month name (abbreviated)
4811 $s_value = date('M',$lNow);
4812 break;
4813 case 'monthname': // month name (full)
4814 $s_value = date('F',$lNow);
4815 break;
4816 case 'year': // year (two digits)
4817 $s_value = date('y',$lNow);
4818 break;
4819 case 'fullyear': // year (full)
4820 $s_value = date('Y',$lNow);
4821 break;
4822 case 'rfcdate': // date formatted according to RFC 822
4823 $s_value = date('r',$lNow);
4824 break;
4825 case 'tzname': // timezone name
4826 $s_value = date('T',$lNow);
4827 break;
4828 case 'tz': // timezone difference from Greenwich +NNNN or -NNNN
4829 $s_value = date('O',$lNow);
4830 break;
4831 case 'hour120': // hour of day (01-12) with possible leading zero
4832 $s_value = date('h',$lNow);
4833 break;
4834 case 'hour240': // hour of day (00-23) with possible leading zero
4835 $s_value = date('H',$lNow);
4836 break;
4837 case 'hour12': // hour of day (1-12) with no leading zero
4838 $s_value = date('g',$lNow);
4839 break;
4840 case 'hour24': // hour of day (0-23) with no leading zero
4841 $s_value = date('G',$lNow);
4842 break;
4843 case 'min': // minute of hour (00-59)
4844 $s_value = date('i',$lNow);
4845 break;
4846 case 'sec': // seconds of minute (00-59)
4847 $s_value = date('s',$lNow);
4848 break;
4849 default:
4850 if ($s_spec{0} == "'")
4851 {
4852 //
4853 // to get a quote, use 3 quotes:
4854 // '''
4855 //
4856 if ($s_spec == "'''")
4857 $s_value = "'";
4858 elseif (substr($s_spec,-1,1) == "'")
4859 $s_value = substr($s_spec,1,-1);
4860 else
4861 //
4862 // missing final quote is OK
4863 //
4864 $s_value = substr($s_spec,1);
4865 }
4866 elseif (strspn($s_spec,"0123456789ABCDEF") == 2)
4867 {
4868 //
4869 // insert the ASCII character corresponding to
4870 // the hexadecimal value
4871 //
4872 $i_val = intval(substr($s_spec,0,2),16);
4873 $s_value = chr($i_val);
4874 }
4875 else
4876 {
4877 //
4878 // look for supported functions, start by getting all
4879 // the tokens
4880 //
4881 $a_toks = GetTokens($s_spec);
4882 if (count($a_toks) > 0)
4883 {
4884 switch ($a_toks[0])
4885 {
4886 case "if":
4887 //
4888 // "if" function: test first field
4889 // if not empty, then use second field
4890 // else, use third field
4891 //
4892 // Example: if(fld1 ; fld2 ; fld3)
4893 //
4894 // tokens are:
4895 // 1 (
4896 // 2 the field name to test (first)
4897 // 3 ;
4898 // 4 the "then" spec (can be missing)
4899 // 5 ;
4900 // 6 the "else" spec (can be missing)
4901 // 7 )
4902 //
4903 if (($n_tok = count($a_toks)) < 6 ||
4904 $a_toks[1] != "(" ||
4905 $a_toks[3] != ";" ||
4906 $a_toks[$n_tok-1] != ")")
4907 SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
4908 array("SPEC"=>$s_spec,
4909 "MSG"=>GetMessage(MSG_DER_FUNC_IF_FMT))));
4910 else
4911 {
4912 $b_ok = true;
4913 $s_fld_name = $a_toks[2];
4914 $s_then_spec = $s_else_spec = "";
4915 for ($ii = 4 ; $ii < $n_tok && $a_toks[$ii] != ';' ; $ii++)
4916 $s_then_spec .= $a_toks[$ii];
4917 if ($ii == $n_tok)
4918 $b_ok = false;
4919 else
4920 {
4921 //
4922 // Concatenate tokens until the ')'.
4923 // This provides the "else" spec.
4924 //
4925 for ( ; ++$ii < $n_tok && $a_toks[$ii] != ')' ; )
4926 $s_else_spec .= $a_toks[$ii];
4927 if ($ii == $n_tok)
4928 $b_ok = false;
4929 }
4930 if ($b_ok)
4931 {
4932 if (!TestFieldEmpty($s_fld_name,$a_form_data,$s_mesg))
4933 $s_fld_spec = $s_then_spec;
4934 else
4935 $s_fld_spec = $s_else_spec;
4936 $s_value = GetDerivedValue($a_form_data,$s_fld_spec);
4937 }
4938 else
4939 SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
4940 array("SPEC"=>$s_spec,
4941 "MSG"=>GetMessage(MSG_DER_FUNC_IF_FMT))));
4942 }
4943 break;
4944 case "size":
4945 if (count($a_toks) != 4 ||
4946 $a_toks[1] != "(" ||
4947 $a_toks[3] != ")")
4948 SendAlert(GetMessage(MSG_DER_FUNC_ERROR,
4949 array("SPEC"=>$s_spec,
4950 "MSG"=>GetMessage(MSG_DER_FUNC_SIZE_FMT))));
4951 elseif (($i_size = GetFileSize($a_toks[2])) !== false)
4952 $s_value = "$i_size";
4953 break;
4954 default:
4955 SendAlert(GetMessage(MSG_UNK_VALUE_SPEC,
4956 array("SPEC"=>$s_spec,"MSG"=>"")));
4957 break;
4958 }
4959 }
4960 else
4961 SendAlert(GetMessage(MSG_UNK_VALUE_SPEC,array("SPEC"=>$s_spec,
4962 "MSG"=>"")));
4963 }
4964 break;
4965 }
4966 return ($s_value);
4967}
4968
4969 //
4970 // Return the value of an object or array as a string.
4971 //
4972function GetObjectAsString($m_value)
4973{
4974 ob_start();
4975 print_r($m_value);
4976 $s_ret = ob_get_contents();
4977 ob_end_clean();
4978 return ($s_ret);
4979}
4980
4981 //
4982 // Return a Server or Environment variable value. Returns false if
4983 // not found, otherwise a string value.
4984 //
4985function GetEnvValue($s_name)
4986{
4987 global $aServerVars,$aEnvVars;
4988
4989 if (isset($aEnvVars[$s_name]))
4990 $m_value = $aEnvVars[$s_name];
4991 elseif (isset($aServerVars[$s_name]))
4992 $m_value = $aServerVars[$s_name];
4993 //
4994 // some values might not be strings - so convert
4995 //
4996 if (isset($m_value) && !is_scalar($m_value))
4997 $m_value = GetObjectAsString($m_value);
4998 return (isset($m_value) ? ((string) $m_value) : false);
4999}
5000
5001 //
5002 // Same as "empty" but checks for true emptiness if ZERO_IS_EMPTY is
5003 // set to false.
5004 //
5005function IsFieldEmpty($s_value)
5006{
5007 if (ZERO_IS_EMPTY || is_array($s_value))
5008 return (empty($s_value));
5009 else
5010 return ($s_value === "");
5011}
5012
5013 //
5014 // Test if a field is set in the given vars array or in the uploaded
5015 // files.
5016 //
5017function IsFieldSet($s_fld,$a_main_vars)
5018{
5019 global $aFileVars;
5020
5021 return (isset($a_main_vars[$s_fld]) ||
5022 (FILEUPLOADS && isset($aFileVars[$s_fld])));
5023}
5024
5025 //
5026 // Return the info for the uploaded file, or false on error.
5027 //
5028function GetFileInfo($s_fld)
5029{
5030 global $aFileVars;
5031
5032 if (FILEUPLOADS && isset($aFileVars[$s_fld]))
5033 {
5034 $a_upload = $aFileVars[$s_fld];
5035 if (isset($a_upload['tmp_name']) && !empty($a_upload['tmp_name']) &&
5036 isset($a_upload['name']) && !empty($a_upload['name']))
5037 {
5038 //
5039 // $a_upload['moved'] is our own internal flag to say we've
5040 // saved the file
5041 //
5042 if ((isset($a_upload['moved']) && $a_upload['moved']) ||
5043 is_uploaded_file($a_upload['tmp_name']))
5044 return ($a_upload);
5045 }
5046 }
5047 return (false);
5048}
5049
5050 //
5051 // Return the original name of the uploaded file or false on error.
5052 //
5053function GetFileName($s_fld)
5054{
5055 if (($a_upload = GetFileInfo($s_fld)) !== false)
5056 return ($a_upload['name']);
5057 return (false);
5058}
5059
5060 //
5061 // Return the size of the uploaded file or false on error.
5062 //
5063function GetFileSize($s_fld)
5064{
5065 if (($a_upload = GetFileInfo($s_fld)) !== false)
5066 return ($a_upload['size']);
5067 return (false);
5068}
5069
5070 //
5071 // Return a field value. Empty string is returned if the field is
5072 // not found. File fields return the original name of the uploaded file.
5073 //
5074function GetFieldValue($s_fld,$a_main_vars)
5075{
5076 if (!isset($a_main_vars[$s_fld]))
5077 {
5078 if (($s_name = GetFileName($s_fld)) === false)
5079 $s_name = "";
5080 return ($s_name);
5081 }
5082 return ((string) $a_main_vars[$s_fld]);
5083}
5084
5085 //
5086 // Tests a field against an array of vars for emptyness.
5087 // If the var isn't found there, then the POSTed files array is checked.
5088 // Returns true if the field is empty (a specific error may
5089 // be returned in the $s_mesg parameter).
5090 //
5091function TestFieldEmpty($s_fld,$a_main_vars,&$s_mesg)
5092{
5093 global $aFileVars;
5094
5095 $s_mesg = "";
5096 $b_empty = TRUE;
5097 if (!isset($a_main_vars[$s_fld]))
5098 {
5099 //
5100 // Each file var is an array with these elements:
5101 // 'name' => The original name of the file on the client machine.
5102 // 'type' => The mime type of the file, if the browser provided this information.
5103 // 'tmp_name' => The temporary filename of the file in which the uploaded file was stored on the server.
5104 // 'error' => The error code associated with this file upload.
5105 // NOTE: 'error' was added in PHP 4.2.0
5106 // 'size' => The size, in bytes, of the uploaded file.
5107 //
5108 // Error codes (the constants are only available from PHP 4.3.0 so
5109 // we have to use the raw numbers):
5110 // UPLOAD_ERR_OK
5111 // Value: 0; There is no error, the file uploaded with success.
5112 // UPLOAD_ERR_INI_SIZE
5113 // Value: 1; The uploaded file exceeds the upload_max_filesize directive in php.ini.
5114 // UPLOAD_ERR_FORM_SIZE
5115 // Value: 2; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form.
5116 // UPLOAD_ERR_PARTIAL
5117 // Value: 3; The uploaded file was only partially uploaded.
5118 // UPLOAD_ERR_NO_FILE
5119 // Value: 4; No file was uploaded.
5120 //
5121 if (FILEUPLOADS && isset($aFileVars[$s_fld]))
5122 {
5123 $a_upload = $aFileVars[$s_fld];
5124 if (isset($a_upload['tmp_name']) && !empty($a_upload['tmp_name']) &&
5125 isset($a_upload['name']) && !empty($a_upload['name']))
5126 {
5127 //
5128 // $a_upload['moved'] is our own internal flag to say we've
5129 // saved the file
5130 //
5131 if ((isset($a_upload['moved']) && $a_upload['moved']) ||
5132 is_uploaded_file($a_upload['tmp_name']))
5133 $b_empty = false;
5134 }
5135 if ($b_empty && isset($a_upload['error']))
5136 switch ($a_upload['error'])
5137 {
5138 case 1:
5139 $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR1);
5140 break;
5141 case 2:
5142 $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR2);
5143 break;
5144 case 3:
5145 $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR3);
5146 break;
5147 case 4:
5148 $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR4);
5149 break;
5150 default:
5151 $s_mesg = GetMessage(MSG_FILE_UPLOAD_ERR_UNK,
5152 array("ERRNO"=>$a_upload['error']));
5153 break;
5154 }
5155 }
5156 }
5157 else
5158 $b_empty = IsFieldEmpty($a_main_vars[$s_fld]);
5159 return ($b_empty);
5160}
5161
5162 //
5163 // Return a derived field value or value specification.
5164 //
5165function GetDerivedValue($a_form_data,$s_word,&$a_errors)
5166{
5167 global $aFileVars;
5168
5169 $s_value = "";
5170 //
5171 // a field name or a value specification
5172 // value specifications have the following format:
5173 // %spec%
5174 //
5175 if (substr($s_word,0,1) == '%')
5176 {
5177 if (substr($s_word,-1,1) != '%')
5178 {
5179 SendAlert(GetMessage(MSG_INV_VALUE_SPEC,array("SPEC"=>$s_word)));
5180 $s_value = $s_word;
5181 }
5182 else
5183 {
5184 $s_spec = substr($s_word,1,-1);
5185 $s_value = ValueSpec($s_spec,$a_form_data,$a_errors);
5186 }
5187 }
5188 else
5189 {
5190 $s_fld_name = $s_word;
5191 //
5192 // try form data first, then the environment/server data
5193 //
5194 if (IsFieldSet($s_fld_name,$a_form_data))
5195 $s_value = GetFieldValue($s_fld_name,$a_form_data);
5196 elseif (($s_value = GetEnvValue($s_fld_name)) === false)
5197 $s_value = "";
5198 $s_value = trim($s_value);
5199 }
5200 return ($s_value);
5201}
5202
5203 //
5204 // Derive a value from the form data using the specification returned
5205 // from ParseDerivation.
5206 //
5207function DeriveValue($a_form_data,$a_value_spec,$s_name,&$a_errors)
5208{
5209 $s_value = "";
5210 for ($ii = 0 ; $ii < count($a_value_spec) ; $ii++)
5211 {
5212 switch ($a_value_spec[$ii])
5213 {
5214 case '+':
5215 //
5216 // concatenate with a single space between, but skip the space
5217 // if the next field is empty
5218 //
5219 if ($ii < count($a_value_spec)-1)
5220 {
5221 $s_temp = GetDerivedValue($a_form_data,$a_value_spec[$ii+1],$a_errors);
5222 if (!IsFieldEmpty($s_temp))
5223 $s_value .= ' ';
5224 }
5225 break;
5226 case '.':
5227 //
5228 // concatenate with no space between
5229 //
5230 break;
5231 case '*':
5232 //
5233 // concatenate with a single space between
5234 //
5235 $s_value .= ' ';
5236 break;
5237 default:
5238 //
5239 // a field name or a value specification
5240 // value specifications have the following format:
5241 // %name%
5242 //
5243 $s_value .= GetDerivedValue($a_form_data,$a_value_spec[$ii],$a_errors);
5244 break;
5245 }
5246 }
5247 return ($s_value);
5248}
5249
5250 //
5251 // Create derived fields specified by the "derive_fields" value.
5252 //
5253function CreateDerived($a_form_data)
5254{
5255 if (isset($a_form_data["derive_fields"]))
5256 {
5257 $a_errors = array();
5258 //
5259 // get the list of derived field specifications
5260 //
5261 $a_list = TrimArray(explode(",",$a_form_data["derive_fields"]));
5262 foreach ($a_list as $s_fld_spec)
5263 {
5264 if ($s_fld_spec === "")
5265 //
5266 // silently ignore empty derivations
5267 //
5268 continue;
5269 if (($i_pos = strpos($s_fld_spec,"=")) === false)
5270 {
5271 $a_errors[] = $s_fld_spec;
5272 continue;
5273 }
5274 $s_name = trim(substr($s_fld_spec,0,$i_pos));
5275 $s_fld_spec = substr($s_fld_spec,$i_pos+1);
5276
5277 if (($a_value_spec = ParseDerivation($a_form_data,$s_fld_spec,
5278 $s_name,$a_errors)) === false)
5279 break;
5280 $a_form_data[$s_name] = DeriveValue($a_form_data,$a_value_spec,$s_name,$a_errors);
5281 }
5282 if (count($a_errors) > 0)
5283 {
5284 SendAlert(GetMessage(MSG_DERIVED_INVALID).implode("\n",$a_errors));
5285 Error("derivation_failure",GetMessage(MSG_INT_FORM_ERROR));
5286 }
5287 }
5288 return ($a_form_data);
5289}
5290
5291 //
5292 // To process the name specification for files and update the
5293 // array of file variables accordingly.
5294 //
5295function SetFileNames($s_name_spec,$a_order,$a_fields,$a_raw_fields,$a_file_vars)
5296{
5297 $a_errors = array();
5298 //
5299 // get the list of file name derivations
5300 //
5301 $a_list = TrimArray(explode(",",$s_name_spec));
5302 foreach ($a_list as $s_fld_spec)
5303 {
5304 if ($s_fld_spec === "")
5305 //
5306 // silently ignore empty file name derivations
5307 //
5308 continue;
5309 if (($i_pos = strpos($s_fld_spec,"=")) === false)
5310 {
5311 $a_errors[] = $s_fld_spec;
5312 continue;
5313 }
5314 $s_name = trim(substr($s_fld_spec,0,$i_pos));
5315 $s_fld_spec = substr($s_fld_spec,$i_pos+1);
5316
5317 if (($a_value_spec = ParseDerivation($a_raw_fields,$s_fld_spec,
5318 $s_name,$a_errors)) === false)
5319 break;
5320 if (isset($a_file_vars[$s_name]) && is_array($a_file_vars[$s_name]))
5321 {
5322 //
5323 // we create our own special entry in the file variable's data
5324 //
5325 $a_file_vars[$s_name]['new_name'] = DeriveValue($a_raw_fields,
5326 $a_value_spec,$s_name,
5327 $a_errors);
5328 //
5329 // we also create (derive) a new field called 'name_of_X'
5330 // where X is the file fields's name
5331 //
5332 ProcessField("name_of_$s_name",$a_file_vars[$s_name]['new_name'],
5333 $a_order,$a_fields,$a_raw_fields);
5334 }
5335 else
5336 SendAlert(GetMessage(MSG_FILE_NAMES_NOT_FILE,
5337 array("NAME"=>$s_name)));
5338 }
5339 if (count($a_errors) > 0)
5340 {
5341 SendAlert(GetMessage(MSG_FILE_NAMES_INVALID).implode("\n",$a_errors));
5342 Error("file_names_derivation_failure",GetMessage(MSG_INT_FORM_ERROR));
5343 }
5344 return (array($a_order,$a_fields,$a_raw_fields,$a_file_vars));
5345}
5346
5347 //
5348 // Process a list of attributes or options.
5349 // Format for each attribute/option:
5350 // name
5351 // or
5352 // name=value
5353 //
5354 // Values can be simple values or semicolon (;) separated lists:
5355 // avalue
5356 // value1;value2;value3;...
5357 //
5358 // Returns attribute/options in the associative array $a_attribs.
5359 // Optionally, valid attributes can be provided in $a_valid_attribs
5360 // (if empty, all attributes found are considered valid).
5361 // Errors are returned in $a_errors.
5362 //
5363function ProcessAttributeList($a_list,&$a_attribs,&$a_errors,
5364 $a_valid_attribs = array())
5365{
5366 $b_got_valid_list = (count($a_valid_attribs) > 0);
5367 foreach ($a_list as $s_attrib)
5368 {
5369 //
5370 // if the name begins with '.' then silently ignore it;
5371 // this allows you to temporarily disable an option without
5372 // getting an alert message
5373 //
5374 if (($i_pos = strpos($s_attrib,"=")) === false)
5375 {
5376 $s_name = trim($s_attrib);
5377 if (empty($s_name) || $s_name{0} == '.')
5378 continue;
5379 //
5380 // option is a simple "present" value
5381 //
5382 $a_attribs[$s_name] = true;
5383 }
5384 else
5385 {
5386 $s_name = trim(substr($s_attrib,0,$i_pos));
5387 if (empty($s_name) || $s_name{0} == '.')
5388 continue;
5389 $s_value_list = substr($s_attrib,$i_pos+1);
5390 if (($i_pos = strpos($s_value_list,";")) === false)
5391 //
5392 // single value
5393 //
5394 $a_attribs[$s_name] = trim($s_value_list);
5395 else
5396 //
5397 // list of values
5398 //
5399 $a_attribs[$s_name] = TrimArray(explode(";",$s_value_list));
5400 }
5401 if ($b_got_valid_list && !isset($a_valid_attribs[$s_name]))
5402 $a_errors[] = $s_name;
5403 }
5404}
5405
5406 //
5407 // Process the options specified in the form.
5408 // Options can be specified in this format:
5409 // option1,option2,option3,...
5410 // Each option can be a simple word or a word and value:
5411 // name
5412 // name=value
5413 // No name or value can contain a comma.
5414 // Values can be simple values or semicolon (;) separated lists:
5415 // avalue
5416 // value1;value2;value3;...
5417 // No value can contain a semicolon.
5418 // Be careful of values beginning and ending with whitespace characters;
5419 // they will be trimmed.
5420 //
5421function ProcessOptions($s_name,$a_form_data,&$a_options,$a_valid_options)
5422{
5423 $a_errors = array();
5424 $a_options = array();
5425 if (isset($a_form_data[$s_name]))
5426 {
5427 //
5428 // get the options list and trim each one
5429 //
5430 $a_list = TrimArray(explode(",",$a_form_data[$s_name]));
5431 ProcessAttributeList($a_list,$a_options,$a_errors,$a_valid_options);
5432 }
5433 if (count($a_errors) > 0)
5434 SendAlert(GetMessage(MSG_OPTIONS_INVALID,array("OPT"=>$s_name)).
5435 implode("\n",$a_errors));
5436}
5437
5438 //
5439 // Process the mail_options specified in the form.
5440 //
5441function ProcessMailOptions($a_form_data)
5442{
5443 global $MAIL_OPTS,$VALID_MAIL_OPTIONS;
5444
5445 ProcessOptions("mail_options",$a_form_data,$MAIL_OPTS,$VALID_MAIL_OPTIONS);
5446}
5447
5448 //
5449 // Check if an option is set
5450 //
5451function IsMailOptionSet($s_name)
5452{
5453 global $MAIL_OPTS;
5454
5455 return (isset($MAIL_OPTS[$s_name]));
5456}
5457
5458 //
5459 // Return an option's value or NULL if not set.
5460 //
5461function GetMailOption($s_name)
5462{
5463 global $MAIL_OPTS;
5464
5465 return (isset($MAIL_OPTS[$s_name]) ? $MAIL_OPTS[$s_name] : NULL);
5466}
5467
5468 //
5469 // Process the crm_options specified in the form.
5470 //
5471function ProcessCRMOptions($a_form_data)
5472{
5473 global $CRM_OPTS,$VALID_CRM_OPTIONS;
5474
5475 ProcessOptions("crm_options",$a_form_data,$CRM_OPTS,$VALID_CRM_OPTIONS);
5476}
5477
5478 //
5479 // Check if an option is set
5480 //
5481function IsCRMOptionSet($s_name)
5482{
5483 global $CRM_OPTS;
5484
5485 return (isset($CRM_OPTS[$s_name]));
5486}
5487
5488 //
5489 // Return an option's value or NULL if not set.
5490 //
5491function GetCRMOption($s_name)
5492{
5493 global $CRM_OPTS;
5494
5495 return (isset($CRM_OPTS[$s_name]) ? $CRM_OPTS[$s_name] : NULL);
5496}
5497
5498 //
5499 // Check if a field is in the mail exclusion list.
5500 //
5501function IsMailExcluded($s_name)
5502{
5503 $a_list = GetMailOption("Exclude");
5504 if (!isset($a_list))
5505 return (false);
5506 if (is_array($a_list))
5507 return (in_array($s_name,$a_list));
5508 else
5509 return ($s_name === $a_list);
5510}
5511
5512 //
5513 // Process the autorespond specified in the form.
5514 //
5515function ProcessAROptions($a_form_data)
5516{
5517 global $AR_OPTS,$VALID_AR_OPTIONS;
5518
5519 ProcessOptions("autorespond",$a_form_data,$AR_OPTS,$VALID_AR_OPTIONS);
5520}
5521
5522 //
5523 // Check if an option is set
5524 //
5525function IsAROptionSet($s_name)
5526{
5527 global $AR_OPTS;
5528
5529 return (isset($AR_OPTS[$s_name]));
5530}
5531
5532 //
5533 // Return an option's value or NULL if not set.
5534 //
5535function GetAROption($s_name)
5536{
5537 global $AR_OPTS;
5538
5539 return (isset($AR_OPTS[$s_name]) ? $AR_OPTS[$s_name] : NULL);
5540}
5541
5542 //
5543 // Process the mail_options specified in the form.
5544 //
5545function ProcessFilterOptions($a_form_data)
5546{
5547 global $FILTER_OPTS,$VALID_FILTER_OPTIONS;
5548
5549 ProcessOptions("filter_options",$a_form_data,$FILTER_OPTS,$VALID_FILTER_OPTIONS);
5550}
5551
5552 //
5553 // Check if an option is set
5554 //
5555function IsFilterOptionSet($s_name)
5556{
5557 global $FILTER_OPTS;
5558
5559 return (isset($FILTER_OPTS[$s_name]));
5560}
5561
5562 //
5563 // Return an option's value or NULL if not set.
5564 //
5565function GetFilterOption($s_name)
5566{
5567 global $FILTER_OPTS;
5568
5569 return (isset($FILTER_OPTS[$s_name]) ? $FILTER_OPTS[$s_name] : NULL);
5570}
5571
5572 //
5573 // Lookup a filter attribute for the given filter.
5574 // Return it's value or false if not set.
5575 //
5576function GetFilterAttrib($s_filter,$s_attrib)
5577{
5578 global $FILTER_ATTRIBS,$FILTER_ATTRIBS_LOOKUP;
5579
5580 if (!isset($FILTER_ATTRIBS[$s_filter]))
5581 //
5582 // no attributes for the filter
5583 //
5584 return (false);
5585 if (!isset($FILTER_ATTRIBS_LOOKUP[$s_filter]))
5586 {
5587 //
5588 // the attributes have not yet been parsed - create the lookup table
5589 //
5590 $a_list = TrimArray(explode(",",$FILTER_ATTRIBS[$s_filter]));
5591 $FILTER_ATTRIBS_LOOKUP[$s_filter] = array();
5592 $a_errors = array();
5593
5594 ProcessAttributeList($a_list,$FILTER_ATTRIBS_LOOKUP[$s_filter],$a_errors);
5595 }
5596 //
5597 // perform the lookup and return the value
5598 //
5599 if (!isset($FILTER_ATTRIBS_LOOKUP[$s_filter][$s_attrib]))
5600 return (false);
5601 return ($FILTER_ATTRIBS_LOOKUP[$s_filter][$s_attrib]);
5602}
5603
5604 //
5605 // Check the filter attributes for the given filter.
5606 // Return true if the given attribute is set otherwise false.
5607 //
5608function IsFilterAttribSet($s_filter,$s_attrib)
5609{
5610 return (GetFilterAttrib($s_filter,$s_attrib));
5611}
5612
5613 //
5614 // Process the given .ini file.
5615 //
5616function ProcessFormIniFile($s_file)
5617{
5618 global $EMAIL_ADDRS;
5619
5620 $a_sections = parse_ini_file($s_file,TRUE);
5621 if (DB_SEE_INI)
5622 {
5623 //
5624 // just display the ini file
5625 //
5626 $s_text = "<p><b>The following settings were found in the file '$s_file':</b></p>";
5627 foreach ($a_sections as $s_sect=>$a_settings)
5628 {
5629 $s_text .= "<p>[$s_sect]\n";
5630 foreach ($a_settings as $s_name=>$s_value)
5631 $s_text .= "$s_name = \"$s_value\"\n";
5632 $s_text .= "</p>";
5633 }
5634 CreatePage($s_text);
5635 exit;
5636 }
5637 //
5638 // Load the email_addresses section.
5639 //
5640 if (isset($a_sections["email_addresses"]))
5641 $EMAIL_ADDRS = $a_sections["email_addresses"];
5642 //
5643 // Process special fields
5644 //
5645 if (isset($a_sections["special_fields"]))
5646 {
5647 foreach ($a_sections["special_fields"] as $s_name=>$m_value)
5648 {
5649 if (IsSpecialField($s_name))
5650 SetSpecialField($s_name,$m_value);
5651 //
5652 // check for multiple valued special fields
5653 //
5654 if (($a_multi_fld = IsSpecialMultiField($s_name)) !== false)
5655 SetSpecialMultiField($a_multi_fld[0],$a_multi_fld[1],$m_value);
5656 }
5657 }
5658}
5659
5660 //
5661 // UnMangle an email address
5662 //
5663function UnMangle($email)
5664{
5665 global $EMAIL_ADDRS;
5666
5667 //
5668 // map from a name to the real email address
5669 //
5670 if (isset($EMAIL_ADDRS[$email]))
5671 $email = $EMAIL_ADDRS[$email];
5672 //
5673 // unmangle
5674 //
5675 if (AT_MANGLE != "")
5676 $email = str_replace(AT_MANGLE,"@",$email);
5677 return ($email);
5678}
5679
5680 //
5681 // Check a list of email addresses (comma separated); returns a list
5682 // of valid email addresses (comma separated).
5683 // The return value is true if there is at least one valid email address.
5684 //
5685function CheckEmailAddress($s_addr,&$s_valid,&$s_invalid)
5686{
5687 global $TARGET_EMAIL;
5688
5689 $s_invalid = $s_valid = "";
5690 $a_list = TrimArray(explode(",",$s_addr));
5691 $a_invalid = array();
5692 for ($ii = 0 ; $ii < count($a_list) ; $ii++)
5693 {
5694 $s_email = UnMangle($a_list[$ii]);
5695 //
5696 // UnMangle works with INI files too, and a single
5697 // word can expand to a list of email addresses.
5698 //
5699 $a_this_list = TrimArray(explode(",",$s_email));
5700 foreach ($a_this_list as $s_email)
5701 {
5702 $b_is_valid = false;
5703 for ($jj = 0 ; $jj < count($TARGET_EMAIL) ; $jj++)
5704 if (eregi($TARGET_EMAIL[$jj],$s_email))
5705 {
5706 if (empty($s_valid))
5707 $s_valid = $s_email;
5708 else
5709 $s_valid .= ",".$s_email;
5710 $b_is_valid = true;
5711 break;
5712 }
5713 if (!$b_is_valid)
5714 $a_invalid[] = $s_email;
5715 }
5716 }
5717 if (count($a_invalid) > 0)
5718 $s_invalid = implode(",",$a_invalid);
5719 return (!empty($s_valid));
5720}
5721
5722 //
5723 // Redirect to another URL
5724 //
5725function Redirect($url)
5726{
5727 //
5728 // for browsers without cookies enabled, append the Session ID
5729 //
5730 if (defined("SID"))
5731 $url = AddURLParams($url,SID);
5732
5733 //
5734 // this is probably a good idea to ensure the session data
5735 // is written away
5736 //
5737 if (function_exists('session_write_close'))
5738 session_write_close();
5739
5740 header("Location: $url");
5741 //
5742 // if the header doesn't work, try JavaScript.
5743 // if that doesn't work, provide a manual link
5744 //
5745 $s_text = GetMessage(MSG_PLSWAIT_REDIR)."\n\n";
5746 $s_text .= "<script language=\"JavaScript\" type=\"text/javascript\">";
5747 $s_text .= "window.location.href = '$url';";
5748 $s_text .= "</script>";
5749 $s_text .= "\n\n".GetMessage(MSG_IFNOT_REDIR,array("URL"=>$url));
5750 CreatePage($s_text);
5751 exit;
5752}
5753
5754 //
5755 // JoinLines is just like "implode" except that it checks
5756 // the end of each array for the separator already being
5757 // there. This allows us to join a mixture of mail
5758 // header lines (already terminated) with body lines.
5759 // This logic works if HEAD_CRLF, for example, is the same
5760 // as BODY_LF (i.e. both "\r\n") or if BODY_LF is the
5761 // same as the last character in HEAD_CRLF (i.e.
5762 // HEAD_CRLF = "\r\n" and BODY_LF = "\n").
5763 // Other value combinations may break things.
5764 //
5765function JoinLines($s_sep,$a_lines)
5766{
5767 $s_str = "";
5768 if (($i_sep_len = strlen($s_sep)) == 0)
5769 //
5770 // no separator
5771 //
5772 return (implode("",$a_lines));
5773 $n_lines = count($a_lines);
5774 for ($ii = 0 ; $ii < $n_lines ; $ii++)
5775 {
5776 $s_line = $a_lines[$ii];
5777 if (substr($s_line,-$i_sep_len) == $s_sep)
5778 $s_str .= $s_line;
5779 else
5780 {
5781 $s_str .= $s_line;
5782 //
5783 // don't append a separator to the last line
5784 //
5785 if ($ii < $n_lines-1)
5786 $s_str .= $s_sep;
5787 }
5788 }
5789 return ($s_str);
5790}
5791
5792 //
5793 // Expands an array of mail headers into mail header lines.
5794 //
5795function ExpandMailHeaders($a_headers)
5796{
5797 $s_hdrs = "";
5798 foreach ($a_headers as $s_name=>$s_value)
5799 if ($s_name != "")
5800 {
5801 if ($s_hdrs != "")
5802 $s_hdrs .= HEAD_CRLF;
5803 $s_hdrs .= $s_name.": ".$s_value;
5804 }
5805 return ($s_hdrs);
5806}
5807
5808 //
5809 // Expands an array of mail headers into an array containing header lines.
5810 //
5811function ExpandMailHeadersArray($a_headers)
5812{
5813 $a_hdrs = array();
5814 foreach ($a_headers as $s_name=>$s_value)
5815 if ($s_name != "")
5816 $a_hdrs[] = $s_name.": ".$s_value.HEAD_CRLF;
5817 return ($a_hdrs);
5818}
5819
5820 //
5821 // Low-level email send function; either calls PHP's mail function
5822 // or uses the PEAR Mail object.
5823 // NOTE: for some errors, there's no point trying to email
5824 // an alert message! So, in these cases, we just display the error to
5825 // the user.
5826 //
5827function DoMail($s_to,$s_subject,$s_mesg,$a_headers)
5828{
5829 global $PEAR_SMTP_HOST,$PEAR_SMTP_PORT,$PEAR_SMTP_USER,$PEAR_SMTP_PWD;
5830
5831 if (isset($PEAR_SMTP_HOST) && !empty($PEAR_SMTP_HOST))
5832 {
5833 require_once("Mail.php");
5834
5835 $a_params = array( "host"=>$PEAR_SMTP_HOST,
5836 "port"=>$PEAR_SMTP_PORT);
5837 if (isset($PEAR_SMTP_USER) && !empty($PEAR_SMTP_USER))
5838 {
5839 $a_params["auth"] = TRUE;
5840 $a_params["username"] = $PEAR_SMTP_USER;
5841 $a_params["password"] = $PEAR_SMTP_PWD;
5842 }
5843 $mailer = Mail::factory("smtp",$a_params);
5844 if (!is_object($mailer))
5845 {
5846 ShowError("pear_error",GetMessage(MSG_PEAR_OBJ),FALSE,FALSE);
5847 exit;
5848 }
5849 if (get_class($mailer) === 'pear_error')
5850 {
5851 ShowError("pear_error",$mailer->getMessage(),FALSE,FALSE);
5852 exit;
5853 }
5854 if (!isset($a_headers['To']) && !isset($a_headers['to']))
5855 $a_headers['To'] = $s_to;
5856 if (!isset($a_headers['Subject']) && !isset($a_headers['subject']))
5857 $a_headers['Subject'] = $s_subject;
5858 $res = $mailer->send($s_to,$a_headers,$s_mesg);
5859 if ($res === TRUE)
5860 return (TRUE);
5861
5862 global $aAlertInfo;
5863
5864 $aAlertInfo[] = GetMessage(MSG_PEAR_ERROR,array("MSG"=>$res->getMessage()));
5865 return (FALSE);
5866 }
5867 return (mail($s_to,$s_subject,$s_mesg,ExpandMailHeaders($a_headers)));
5868}
5869
5870 //
5871 // Send an email
5872 //
5873function SendCheckedMail($to,$subject,$mesg,$sender,$a_headers = array())
5874{
5875 global $PEAR_SMTP_HOST;
5876
5877 $b_f_option = false;
5878 $b_form_option = IsMailOptionSet("SendMailFOption"); // this is superseded, but still supported
5879 if (SENDMAIL_F_OPTION || $b_form_option)
5880 {
5881 if (empty($sender))
5882 {
5883 //
5884 // SENDMAIL_F_OPTION with no sender is silently ignored
5885 //
5886 if ($b_form_option)
5887 {
5888 //
5889 // form has specified SendMailFOption, but there's no
5890 // sender address
5891 //
5892 static $b_in_here = false;
5893 global $SERVER;
5894
5895 if (!$b_in_here) // prevent infinite recursion
5896 {
5897 $b_in_here = true;
5898 SendAlert(GetMessage(MSG_NO_FOPT_ADDR));
5899 $b_in_here = false;
5900 }
5901 //
5902 // if there's no from address, create a dummy one
5903 //
5904 $sender = "dummy@".(isset($SERVER) ? $SERVER : "UnknownServer");
5905 $a_headers['From'] = $sender;
5906 $b_f_option = true;
5907 }
5908 }
5909 else
5910 $b_f_option = true;
5911 }
5912 if (INI_SET_FROM && !empty($sender))
5913 ini_set('sendmail_from',$sender);
5914
5915 if ((!isset($PEAR_SMTP_HOST) || empty($PEAR_SMTP_HOST)) && $b_f_option)
5916 return (mail($to,$subject,$mesg,ExpandMailHeaders($a_headers),"-f$sender"));
5917 else
5918 return (DoMail($to,$subject,$mesg,$a_headers));
5919}
5920
5921 //
5922 // Send an alert email
5923 //
5924function SendAlert($s_error,$b_filter = true,$b_non_error = false)
5925{
5926 global $SPECIAL_VALUES,$FORMATTED_INPUT,$FROM_USER,$aServerVars,$aStrippedFormVars;
5927 global $aAlertInfo;
5928
5929 $s_error = str_replace("\n",BODY_LF,$s_error);
5930 $b_got_filter = (isset($SPECIAL_VALUES["filter"]) && !empty($SPECIAL_VALUES["filter"]));
5931
5932 //
5933 // if there is a filter specified and we're not sending the alert
5934 // through the filter, don't show the user's data. This is
5935 // on the assumption that the filter is an encryption program; so,
5936 // we don't want to send the user's data in clear text inside the
5937 // alerts.
5938 //
5939 $b_show_data = true;
5940 if ($b_got_filter && !$b_filter)
5941 $b_show_data = false;
5942
5943 $s_form_subject = $s_alert_to = "";
5944 $b_check = true;
5945 //
5946 // might be too early to have $SPECIAL_VALUES set, so
5947 // look in the form vars too
5948 //
5949 if (isset($SPECIAL_VALUES["alert_to"]))
5950 $s_alert_to = trim($SPECIAL_VALUES["alert_to"]);
5951 if (empty($s_alert_to) && isset($aStrippedFormVars["alert_to"]))
5952 $s_alert_to = trim($aStrippedFormVars["alert_to"]);
5953
5954 if (isset($SPECIAL_VALUES["subject"]))
5955 $s_form_subject = trim($SPECIAL_VALUES["subject"]);
5956 if (empty($s_form_subject) && isset($aStrippedFormVars["subject"]))
5957 $s_form_subject = trim($aStrippedFormVars["subject"]);
5958
5959 if (empty($s_alert_to))
5960 {
5961 $s_alert_to = DEF_ALERT;
5962 $b_check = false;
5963 }
5964 if (!empty($s_alert_to))
5965 {
5966 $s_from_addr = $s_from = "";
5967 $a_headers = array();
5968 if (isset($FROM_USER) && !empty($FROM_USER))
5969 {
5970 if ($FROM_USER != "NONE")
5971 {
5972 $a_headers['From'] = $FROM_USER;
5973 $s_from = "From: $FROM_USER";
5974 $s_from_addr = $FROM_USER;
5975 }
5976 }
5977 else
5978 {
5979 global $SERVER;
5980
5981 $s_from_addr = "FormMail@".$SERVER;
5982 $a_headers['From'] = $s_from_addr;
5983 $s_from = "From: $s_from_addr";
5984 }
5985 $s_mesg = "To: ".UnMangle($s_alert_to).BODY_LF;
5986 if (!empty($s_from))
5987 $s_mesg .= $s_from.BODY_LF;
5988 $s_mesg .= BODY_LF;
5989 if (count($aAlertInfo) > 0)
5990 {
5991 if ($b_show_data)
5992 {
5993 $s_error .= BODY_LF.GetMessage(MSG_MORE_INFO).BODY_LF;
5994 $s_error .= implode(BODY_LF,$aAlertInfo);
5995 }
5996 else
5997 $s_error .= BODY_LF.GetMessage(MSG_INFO_STOPPED).BODY_LF;
5998 }
5999 if ($b_non_error)
6000 {
6001 $s_mesg .= $s_error.BODY_LF.BODY_LF;
6002 $s_subj = GetMessage(MSG_FM_ALERT);
6003 if (!empty($s_form_subject))
6004 $s_subj .= " ($s_form_subject)";
6005 }
6006 else
6007 {
6008 $s_mesg .= GetMessage(MSG_FM_ERROR_LINE).BODY_LF.
6009 $s_error.BODY_LF.BODY_LF;
6010 $s_subj = GetMessage(MSG_FM_ERROR);
6011 if (!empty($s_form_subject))
6012 $s_subj .= " ($s_form_subject)";
6013 if ($b_show_data)
6014 $s_mesg .= implode(BODY_LF,$FORMATTED_INPUT);
6015 else
6016 $s_mesg .= GetMessage(MSG_USERDATA_STOPPED);
6017 }
6018 if ($b_filter && $b_got_filter)
6019 $s_mesg = GetMessage(MSG_FILTERED,
6020 array("FILTER"=>$SPECIAL_VALUES["filter"])).
6021 BODY_LF.BODY_LF.
6022 Filter($SPECIAL_VALUES["filter"],$s_mesg);
6023 if (isset($aServerVars['HTTP_REFERER']))
6024 $s_mesg .= BODY_LF.BODY_LF."Referring page was ".$aServerVars['HTTP_REFERER'];
6025 elseif (isset($SPECIAL_VALUES['this_form']) && $SPECIAL_VALUES['this_form'] !== "")
6026 $s_mesg .= BODY_LF.BODY_LF."Referring form was ".$SPECIAL_VALUES['this_form'];
6027
6028 if (isset($aServerVars['REMOTE_ADDR']))
6029 $s_mesg .= BODY_LF.BODY_LF."User IP address was ".$aServerVars['REMOTE_ADDR'];
6030
6031 if ($b_check)
6032 {
6033 if (CheckEmailAddress($s_alert_to,$s_valid,$s_invalid))
6034 return (SendCheckedMail($s_valid,$s_subj,$s_mesg,$s_from_addr,$a_headers));
6035 }
6036 else
6037 return (SendCheckedMail($s_alert_to,$s_subj,$s_mesg,$s_from_addr,$a_headers));
6038 }
6039 return (false);
6040}
6041
6042 //
6043 // Read the lines in a file and return an array.
6044 // Each line is stripped of line termination characters.
6045 //
6046function ReadLines($fp)
6047{
6048 $a_lines = array();
6049 while (!feof($fp))
6050 {
6051 $s_line = fgets($fp,4096);
6052 //
6053 // strip carriage returns and line feeds
6054 //
6055 $s_line = str_replace("\r","",$s_line);
6056 $s_line = str_replace("\n","",$s_line);
6057 $a_lines[] = $s_line;
6058 }
6059 return ($a_lines);
6060}
6061
6062 //
6063 // Open a URL and return the data from it as a string.
6064 // Returns false on failure ($s_error has the error string)
6065 //
6066function GetURL($s_url,&$s_error)
6067{
6068 global $php_errormsg,$aServerVars,$FM_VERS;
6069 global $AUTHENTICATE,$AUTH_USER,$AUTH_PW;
6070
6071 //
6072 // parse the URL to get the component parts
6073 //
6074 $a_parts = parse_url($s_url);
6075 //
6076 // must have a host
6077 //
6078 if (!isset($a_parts["host"]))
6079 {
6080 $s_error = GetMessage(MSG_URL_PARSE);
6081 return (false);
6082 }
6083 $s_host_hdr = $a_parts["host"];
6084 //
6085 // if no port number is given, we support http and https
6086 //
6087 if (!isset($a_parts["port"]))
6088 {
6089 if (!isset($a_parts["scheme"]) || strtolower($a_parts["scheme"]) == "http")
6090 $a_parts["port"] = 80;
6091 elseif (strtolower($a_parts["scheme"]) == "https")
6092 $a_parts["port"] = 443;
6093 else
6094 {
6095 $s_error = GetMessage(MSG_URL_SCHEME,
6096 array("SCHEME"=>$a_parts["scheme"]));
6097 return (false);
6098 }
6099 }
6100 if ($a_parts["port"] == 443)
6101 //
6102 // fsockopen requires ssl:// in the host name
6103 //
6104 $a_parts["host"] = "ssl://".$a_parts["host"];
6105
6106 //
6107 // default the path if empty
6108 //
6109 if (!isset($a_parts["path"]) || $a_parts["path"] === "")
6110 $a_parts["path"] = "/";
6111
6112 $f_sock = @fsockopen($a_parts["host"],(int) $a_parts["port"],$i_errno,$s_errstr,30);
6113 if ($f_sock === false)
6114 {
6115 $s_error = GetMessage(MSG_SOCKET,
6116 array("ERRNO"=>$i_errno,
6117 "ERRSTR"=>$s_errstr,
6118 "PHPERR"=>isset($php_errormsg) ? $php_errormsg : ""));
6119 return (false);
6120 }
6121
6122 //
6123 // the GET request
6124 //
6125 fputs($f_sock,"GET ".$a_parts["path"]." HTTP/1.0\r\n");
6126
6127 //
6128 // Determine authentication requirements
6129 //
6130 if ($AUTHENTICATE !== "" || $AUTH_USER !== "" || $AUTH_PW !== "")
6131 {
6132 if ($AUTHENTICATE === "")
6133 fputs($f_sock,"Authorization: Basic ".
6134 base64_encode("$AUTH_USER:$AUTH_PW")."\r\n");
6135 else
6136 fputs($f_sock,"Authorization: $AUTHENTICATE\r\n");
6137
6138 }
6139 else
6140 {
6141 if (isset($a_parts["user"]) || isset($a_parts["pass"]))
6142 {
6143 $s_auth_user = isset($a_parts["user"]) ? $a_parts["user"] : "";
6144 $s_auth_pass = isset($a_parts["pass"]) ? $a_parts["pass"] : "";
6145 }
6146 else
6147 {
6148 $s_auth_type = isset($aServerVars["PHP_AUTH_TYPE"]) ? $aServerVars["PHP_AUTH_TYPE"] : "";
6149 $s_auth_user = isset($aServerVars["PHP_AUTH_USER"]) ? $aServerVars["PHP_AUTH_USER"] : "";
6150 $s_auth_pass = isset($aServerVars["PHP_AUTH_PW"]) ? $aServerVars["PHP_AUTH_PW"] : "";
6151 }
6152 if (!isset($s_auth_type) || $s_auth_type === "")
6153 $s_auth_type = "Basic";
6154 //
6155 // Add the authentication header
6156 //
6157 if ($s_auth_user !== "" || $s_auth_pass !== "")
6158 fputs($f_sock,"Authorization: $s_auth_type ".
6159 base64_encode("$s_auth_user:$s_auth_pass")."\r\n");
6160 }
6161
6162 //
6163 // Specify the host name
6164 //
6165 fputs($f_sock,"Host: $s_host_hdr\r\n");
6166 //
6167 // Specify the user agent
6168 //
6169 fputs($f_sock,"User-Agent: FormMail/$FM_VERS (from www.tectite.com)\r\n");
6170 //
6171 // Accept any output
6172 //
6173 fputs($f_sock,"Accept: */*\r\n");
6174 //
6175 // End of request headers
6176 //
6177 fputs($f_sock,"\r\n");
6178
6179 //
6180 // Read and parse the response header
6181 //
6182 $i_http_code = 0;
6183 $s_status = "";
6184 while (!feof($f_sock))
6185 {
6186 $s_line = fgets($f_sock,4096);
6187 if ($s_line == "\r\n" || $s_line == "\n")
6188 break;
6189 if (substr($s_line,0,4) == "HTTP")
6190 {
6191 $i_pos = strpos($s_line," ");
6192 $s_status = substr($s_line,$i_pos+1);
6193 $i_end_pos = strpos($s_status," ");
6194 if ($i_end_pos === false)
6195 $i_end_pos = strlen($s_status);
6196 $i_http_code = (int) substr($s_status,0,$i_end_pos);
6197 }
6198 }
6199 if ($i_http_code < 200 || $i_http_code > 299)
6200 {
6201 $s_error = GetMessage(MSG_GETURL_OPEN,array("STATUS"=>$s_status));
6202 fclose($f_sock);
6203 return (false);
6204 }
6205 //
6206 // read content into one big string buffer and return
6207 //
6208 $s_buf = "";
6209 while (!feof($f_sock))
6210 $s_buf .= fread($f_sock,1024);
6211 fclose($f_sock);
6212 return ($s_buf);
6213}
6214
6215 //
6216 // Load a template file into a string.
6217 //
6218function LoadTemplate($s_name,$s_dir,$s_url,$b_ret_lines = false)
6219{
6220 global $php_errormsg;
6221
6222 $s_buf = "";
6223 $a_lines = array();
6224 if (!empty($s_dir))
6225 {
6226 $s_name = "$s_dir/".basename($s_name);
6227@ $fp = fopen($s_name,"r");
6228 if ($fp === false)
6229 {
6230 SendAlert(GetMessage(MSG_OPEN_TEMPLATE,array("NAME"=>$s_name,
6231 "ERROR"=>CheckString($php_errormsg))));
6232 return (false);
6233 }
6234 if ($b_ret_lines)
6235 $a_lines = ReadLines($fp);
6236 else
6237 //
6238 // load the whole template into a string
6239 //
6240 $s_buf = fread($fp,filesize($s_name));
6241 fclose($fp);
6242 }
6243 else
6244 {
6245 global $aServerVars;
6246
6247 $s_name = "$s_url/".basename($s_name);
6248 if (isset($aServerVars['HTTP_USER_AGENT']))
6249 $s_name = AddURLParams($s_name,"USER_AGENT=".$aServerVars['HTTP_USER_AGENT']);
6250
6251@ $fp = fopen($s_name,"r");
6252 if ($fp === false)
6253 {
6254 SendAlert(GetMessage(MSG_OPEN_TEMPLATE,array("NAME"=>$s_name,
6255 "ERROR"=>CheckString($php_errormsg))));
6256 return (false);
6257 }
6258 if ($b_ret_lines)
6259 $a_lines = ReadLines($fp);
6260 else
6261 //
6262 // load the whole template into a string
6263 //
6264 while (!feof($fp))
6265 $s_buf .= fread($fp,4096);
6266 fclose($fp);
6267 }
6268 return ($b_ret_lines ? $a_lines : $s_buf);
6269}
6270
6271 //
6272 // To show an error template. The template must be HTML and, for security
6273 // reasons, must be a file on the server in the directory specified
6274 // by $TEMPLATEDIR or $TEMPLATEURL.
6275 // $a_specs is an array of substitutions to perform, as follows:
6276 // tag-name replacement string
6277 //
6278 // For example:
6279 // "fmerror"=>"An error message"
6280 //
6281function ShowErrorTemplate($s_name,$a_specs,$b_user_error)
6282{
6283 global $TEMPLATEURL,$TEMPLATEDIR;
6284
6285 if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
6286 {
6287 SendAlert(GetMessage(MSG_TEMPLATES));
6288 return (false);
6289 }
6290 if (($s_buf = LoadTemplate($s_name,$TEMPLATEDIR,$TEMPLATEURL)) === false)
6291 return (false);
6292
6293 //
6294 // now look for the tags to replace
6295 //
6296 foreach ($a_specs as $s_tag=>$s_value)
6297 //
6298 // search for
6299 // <tagname/>
6300 // with optional whitespace
6301 //
6302 $s_buf = preg_replace('/<\s*'.preg_quote($s_tag,"/").'\s*\/\s*>/ims',
6303 nl2br($s_value),$s_buf);
6304 if ($b_user_error)
6305 {
6306 // strip any <fmusererror> and </fmusererror> tags
6307 //
6308 // You can show information that's specific to user
6309 // errors between these special tags.
6310 //
6311 $s_buf = preg_replace('/<\s*\/?\s*fmusererror\s*>/ims','',$s_buf);
6312 //
6313 // since this isn't a system error, strip anything between
6314 // <fmsyserror> and </fmsyserror>
6315 //
6316 $s_buf = preg_replace('/<\s*fmsyserror\s*>.*<\s*\/\s*fmsyserror\s*>/ims','',$s_buf);
6317 }
6318 else
6319 {
6320 // strip any <fmsyserror> and </fmsyserror> tags
6321 //
6322 // You can show information that's specific to system
6323 // errors between these special tags.
6324 //
6325 $s_buf = preg_replace('/<\s*\/?\s*fmsyserror\s*>/ims','',$s_buf);
6326 //
6327 // since this isn't a user error, strip anything between
6328 // <fmusererror> and </fmusererror>
6329 //
6330 $s_buf = preg_replace('/<\s*fmusererror\s*>.*<\s*\/\s*fmusererror\s*>/ims','',$s_buf);
6331 }
6332 //
6333 // just output the page
6334 //
6335 echo $s_buf;
6336 return (true);
6337}
6338
6339 //
6340 // To show an error to the user.
6341 //
6342function ShowError($error_code,$error_mesg,$b_user_error,
6343 $b_alerted = false,$a_item_list = array(),$s_extra_info = "")
6344{
6345 global $SPECIAL_FIELDS,$SPECIAL_MULTI,$SPECIAL_VALUES;
6346 global $aServerVars,$aSessionVars,$aStrippedFormVars;
6347
6348 //
6349 // Testing with PHP 4.0.6 indicates that sessions don't always work.
6350 // So, we'll also add the error to the URL, unless
6351 // PUT_DATA_IN_URL is false.
6352 //
6353 $aSessionVars["FormError"] = $error_mesg;
6354 $aSessionVars["FormErrorInfo"] = $s_extra_info;
6355 $aSessionVars["FormErrorCode"] = $error_code;
6356 $aSessionVars["FormErrorItems"] = $a_item_list;
6357 $aSessionVars["FormIsUserError"] = $b_user_error;
6358 $aSessionVars["FormAlerted"] = $b_alerted;
6359 $aSessionVars["FormData"] = array();
6360
6361 $bad_url = $SPECIAL_VALUES["bad_url"];
6362 $bad_template = $SPECIAL_VALUES["bad_template"];
6363 $this_form = $SPECIAL_VALUES["this_form"];
6364 if (!empty($bad_url))
6365 {
6366 $a_params = array();
6367 $a_params[] = "this_form=".urlencode("$this_form");
6368 $a_params[] = "bad_template=".urlencode("$bad_template");
6369 if (PUT_DATA_IN_URL)
6370 {
6371 $a_params[] = "error=".urlencode("$error_mesg");
6372 $a_params[] = "extra=".urlencode("$s_extra_info");
6373 $a_params[] = "errcode=".urlencode("$error_code");
6374 $a_params[] = "isusererror=".($b_user_error ? "1" : "0");
6375 $a_params[] = "alerted=".($b_alerted ? "1" : "0");
6376 $i_count = 1;
6377 foreach ($a_item_list as $s_item)
6378 {
6379 $a_params[] = "erroritem$i_count=".urlencode("$s_item");
6380 $i_count++;
6381 }
6382 }
6383 else
6384 //
6385 // tell the bad_url to look in the session only
6386 //
6387 $a_params[] = "insession=1";
6388 //
6389 // Add the posted data to the URL so that an intelligent
6390 // $bad_url can call the form again
6391 //
6392 foreach ($aStrippedFormVars as $s_name=>$m_value)
6393 {
6394 //
6395 // skip special fields
6396 //
6397 $b_special = false;
6398 if (in_array($s_name,$SPECIAL_FIELDS))
6399 $b_special = true;
6400 else
6401 {
6402 foreach ($SPECIAL_MULTI as $s_multi_fld)
6403 {
6404 $i_len = strlen($s_multi_fld);
6405 if (substr($s_name,0,$i_len) == $s_multi_fld)
6406 {
6407 $i_index = (int) substr($s_name,$i_len);
6408 if ($i_index > 0)
6409 {
6410 $b_special = true;
6411 break;
6412 }
6413 }
6414 }
6415 }
6416 if (!$b_special)
6417 {
6418 if (PUT_DATA_IN_URL)
6419 {
6420 if (is_array($m_value))
6421 foreach ($m_value as $s_value)
6422 $a_params[] = "$s_name".'[]='.
6423 urlencode(substr($s_value,0,MAXSTRING));
6424 else
6425 $a_params[] = "$s_name=".urlencode(substr($m_value,0,MAXSTRING));
6426 }
6427 else
6428 {
6429 if (is_array($m_value))
6430 $aSessionVars["FormData"]["$s_name"] = $m_value;
6431 else
6432 $aSessionVars["FormData"]["$s_name"] = substr($m_value,0,MAXSTRING);
6433 }
6434 }
6435 }
6436 //
6437 // Now add the authentication data, if any
6438 //
6439 if ((isset($aServerVars["PHP_AUTH_USER"]) &&
6440 $aServerVars["PHP_AUTH_USER"] !== "") ||
6441 (isset($aServerVars["PHP_AUTH_PW"]) &&
6442 $aServerVars["PHP_AUTH_PW"] !== ""))
6443 {
6444 if (PUT_DATA_IN_URL)
6445 {
6446 if (isset($aServerVars["PHP_AUTH_USER"]))
6447 $a_params[] = "PHP_AUTH_USER=".urlencode($aServerVars["PHP_AUTH_USER"]);
6448
6449 if (isset($aServerVars["PHP_AUTH_PW"]))
6450 $a_params[] = "PHP_AUTH_PW=".urlencode($aServerVars["PHP_AUTH_PW"]);
6451
6452 if (isset($aServerVars["PHP_AUTH_TYPE"]))
6453 $a_params[] = "PHP_AUTH_TYPE=".urlencode($aServerVars["PHP_AUTH_TYPE"]);
6454 }
6455 else
6456 {
6457 if (isset($aServerVars["PHP_AUTH_USER"]))
6458 $aSessionVars["FormData"]["PHP_AUTH_USER"] = $aServerVars["PHP_AUTH_USER"];
6459
6460 if (isset($aServerVars["PHP_AUTH_PW"]))
6461 $aSessionVars["FormData"]["PHP_AUTH_PW"] = $aServerVars["PHP_AUTH_PW"];
6462
6463 if (isset($aServerVars["PHP_AUTH_TYPE"]))
6464 $aSessionVars["FormData"]["PHP_AUTH_TYPE"] = $aServerVars["PHP_AUTH_TYPE"];
6465 }
6466 }
6467 $bad_url = AddURLParams($bad_url,$a_params,false);
6468 Redirect($bad_url);
6469 }
6470 else
6471 {
6472 if (!empty($bad_template))
6473 {
6474 $a_specs = array("fmerror"=>htmlspecialchars("$error_mesg"),
6475 "fmerrorcode"=>htmlspecialchars("$error_code"),
6476 "fmfullerror"=>htmlspecialchars("$error_mesg")."\n".
6477 htmlspecialchars("$s_extra_info"),
6478 "fmerrorextra"=>htmlspecialchars("$s_extra_info"),);
6479 $i_count = 1;
6480 foreach ($a_item_list as $s_item)
6481 {
6482 $a_specs["fmerroritem$i_count"] = htmlspecialchars($s_item);
6483 $i_count++;
6484 }
6485 $s_list = "";
6486 foreach ($a_item_list as $s_item)
6487 $s_list .= "<li>".htmlspecialchars($s_item)."</li>\n";
6488 $a_specs["fmerroritemlist"] = $s_list;
6489 if (ShowErrorTemplate($bad_template,$a_specs,$b_user_error))
6490 return;
6491 }
6492 $s_text = GetMessage(MSG_ERROR_PROC);
6493 if ($b_user_error)
6494 $s_text .= $error_mesg."\n".$s_extra_info;
6495 else
6496 {
6497 if ($b_alerted)
6498 $s_text .= GetMessage(MSG_ALERT_DONE);
6499 else
6500 $s_text .= GetMessage(MSG_PLS_CONTACT);
6501 $s_text .= GetMessage(MSG_APOLOGY);
6502 }
6503 CreatePage($s_text);
6504 //
6505 // the session data is not needed now
6506 //
6507 ZapSession();
6508 }
6509}
6510
6511 //
6512 // Report an error
6513 //
6514function Error($error_code,$error_mesg,$b_filter = true,$show = true,$int_mesg = "")
6515{
6516 $b_alerted = false;
6517 if (SendAlert("$error_code\n *****$int_mesg*****\nError=$error_mesg\n",$b_filter))
6518 $b_alerted = true;
6519 if ($show)
6520 ShowError($error_code,$error_mesg,false,$b_alerted);
6521 else
6522 //
6523 // show something to the user
6524 //
6525 ShowError($error_code,GetMessage(MSG_SUBM_FAILED),false,$b_alerted);
6526 exit;
6527}
6528
6529 //
6530 // Report a user error
6531 //
6532function UserError($s_error_code,$s_error_mesg,
6533 $s_extra_info = "",$a_item_list = array())
6534{
6535 $b_alerted = false;
6536 if (ALERT_ON_USER_ERROR &&
6537 SendAlert("$s_error_code\nError=$s_error_mesg\n$s_extra_info\n"))
6538 $b_alerted = true;
6539 ShowError($s_error_code,$s_error_mesg,true,$b_alerted,$a_item_list,$s_extra_info);
6540 exit;
6541}
6542
6543 //
6544 // Create a simple page with the given text.
6545 //
6546function CreatePage($text)
6547{
6548 global $FM_VERS;
6549
6550 echo "<html>";
6551 echo "<head>";
6552 echo "</head>";
6553 echo "<body>";
6554 echo nl2br($text);
6555 echo "<p /><p><small>";
6556 echo GetMessage(MSG_ABOUT_FORMMAIL,array("FM_VERS"=>$FM_VERS,
6557 "TECTITE"=>"www.tectite.com"));
6558 echo "</small></p>";
6559 echo "</body>";
6560 echo "</html>";
6561}
6562
6563 //
6564 // Strip slashes if magic_quotes_gpc is set.
6565 //
6566function StripGPC($s_value)
6567{
6568 if (get_magic_quotes_gpc() != 0)
6569 $s_value = stripslashes($s_value);
6570 return ($s_value);
6571}
6572
6573 //
6574 // return an array, stripped of slashes if magic_quotes_gpc is set
6575 //
6576function StripGPCArray($a_values)
6577{
6578 if (get_magic_quotes_gpc() != 0)
6579 foreach ($a_values as $m_key=>$m_value)
6580 if (is_array($m_value))
6581 //
6582 // strip arrays recursively
6583 //
6584 $a_values[$m_key] = StripGPCArray($m_value);
6585 else
6586 //
6587 // convert scalar to string and strip
6588 //
6589 $a_values[$m_key] = stripslashes("$m_value");
6590 return ($a_values);
6591}
6592
6593 //
6594 // Strip a value of unwanted characters, which might be hacks.
6595 // If $b_conv_quotes is true, also swaps all double quotes with single quotes.
6596 //
6597function Strip($value,$b_conv_quotes = true)
6598{
6599 if ($b_conv_quotes)
6600 //
6601 // "standard" quote conversion
6602 //
6603 $value = str_replace("\"","'",$value);
6604 $value = preg_replace('/[[:cntrl:][:space:]]+/'," ",$value); // zap all control chars and multiple blanks
6605 return ($value);
6606}
6607
6608 //
6609 // Clean a value. This means:
6610 // 1. convert to string
6611 // 2. truncate to maximum length
6612 // 3. strip the value of unwanted or dangerous characters (hacks)
6613 // 4. trim both ends of whitespace
6614 // Each element of an array is cleaned as above. This process occurs
6615 // recursively, so arrays of arrays work OK too (though there's no
6616 // need for that in this program).
6617 //
6618 // Non-scalar values are changed to the string "<X>" where X is the type.
6619 // In general, FormMail won't receive non-scalar non-array values, so this
6620 // is more a future-proofing measure.
6621 //
6622function CleanValue($m_value,$b_conv_quotes = true)
6623{
6624 if (is_array($m_value))
6625 {
6626 foreach ($m_value as $m_key=>$m_item)
6627 $m_value[$m_key] = CleanValue($m_item,$b_conv_quotes);
6628 }
6629 elseif (!is_scalar($m_value))
6630 $m_value = "<".gettype($m_value).">";
6631 else
6632 {
6633 //
6634 // convert to string and truncate
6635 //
6636 $m_value = substr("$m_value",0,MAXSTRING);
6637 //
6638 // strip unwanted chars and trim
6639 //
6640 $m_value = trim(Strip($m_value,$b_conv_quotes));
6641 }
6642 return ($m_value);
6643}
6644
6645 //
6646 // Clean a special value. Special values listed in $SPECIAL_NOSTRIP
6647 // will not be cleaned.
6648 //
6649function SpecialCleanValue($s_name,$m_value)
6650{
6651 global $SPECIAL_NOSTRIP;
6652
6653 if (!in_array($s_name,$SPECIAL_NOSTRIP))
6654 $m_value = CleanValue($m_value);
6655 return ($m_value);
6656}
6657
6658 //
6659 // Return the fields and their values in a string containing one
6660 // field per line.
6661 //
6662function MakeFieldOutput($a_order,$a_fields,$s_line_feed = BODY_LF)
6663{
6664 $n_order = count($a_order);
6665 $s_output = "";
6666 for ($ii = 0 ; $ii < $n_order ; $ii++)
6667 {
6668 $s_name = $a_order[$ii];
6669 if (isset($a_fields[$s_name]))
6670 $s_output .= "$s_name: ".$a_fields[$s_name].$s_line_feed;
6671 }
6672 return ($s_output);
6673}
6674
6675 //
6676 // Check if a field name is special. Returns true if it is.
6677 //
6678function IsSpecialField($s_name)
6679{
6680 global $SPECIAL_FIELDS;
6681
6682 return (in_array($s_name,$SPECIAL_FIELDS));
6683}
6684
6685 //
6686 // Set a special field value.
6687 //
6688function SetSpecialField($s_name,$m_value)
6689{
6690 global $SPECIAL_VALUES;
6691
6692 //
6693 // special values cannot be arrays; ignore them if they are
6694 //
6695 if (!is_array($m_value))
6696 $SPECIAL_VALUES[$s_name] = SpecialCleanValue($s_name,$m_value);
6697}
6698
6699 //
6700 // Check if a field name is a special "multi" field.
6701 // A multi field is the name plus a sequence number. For example,
6702 // conditions1
6703 // conditions2
6704 // Returns a list (array) if it is, otherwise false if not.
6705 // The list contains:
6706 // 1. the name of the special multi field
6707 // 2. the index number for multi field
6708 //
6709function IsSpecialMultiField($s_name)
6710{
6711 global $SPECIAL_MULTI;
6712
6713 foreach ($SPECIAL_MULTI as $s_multi_fld)
6714 {
6715 $i_len = strlen($s_multi_fld);
6716 //
6717 // look for nameN where N is a number starting from 1
6718 //
6719 if (substr($s_name,0,$i_len) == $s_multi_fld)
6720 {
6721 $i_index = (int) substr($s_name,$i_len);
6722 if ($i_index > 0)
6723 {
6724 //
6725 // re-index to zero
6726 //
6727 --$i_index;
6728 return (array($s_multi_fld,$i_index));
6729 }
6730 }
6731 }
6732 return (false);
6733}
6734
6735 //
6736 // Set a multi field value.
6737 //
6738function SetSpecialMultiField($s_name,$i_index,$m_value)
6739{
6740 global $SPECIAL_VALUES;
6741
6742 //
6743 // special fields cannot be arrays - ignore if it is
6744 //
6745 if (!is_array($m_value))
6746 $SPECIAL_VALUES[$s_name][$i_index] = SpecialCleanValue($s_name,$m_value);
6747}
6748
6749 //
6750 // Process a field
6751 //
6752function ProcessField($s_name,$raw_value,&$a_order,&$a_fields,&$a_raw_fields)
6753{
6754 global $FORMATTED_INPUT;
6755
6756 //
6757 // fields go into an array of special values or an array of other values
6758 //
6759 $b_special = false;
6760 if (IsSpecialField($s_name))
6761 {
6762 SetSpecialField($s_name,$raw_value);
6763 $b_special = true;
6764 }
6765 //
6766 // check for multiple valued special fields
6767 //
6768 if (($a_multi_fld = IsSpecialMultiField($s_name)) !== false)
6769 {
6770 SetSpecialMultiField($a_multi_fld[0],$a_multi_fld[1],$raw_value);
6771 $b_special = true;
6772 }
6773 if (!$b_special)
6774 {
6775 //
6776 // return the raw value unchanged in the $a_raw_fields array
6777 //
6778 $a_raw_fields[$s_name] = $raw_value;
6779 //
6780 // handle checkboxes and multiple-selection lists
6781 // Thanks go to Theodore Boardman for the suggestion
6782 // and initial working code.
6783 //
6784 if (is_array($raw_value))
6785 {
6786 //
6787 // the array must be an array of scalars (not an array
6788 // of arrays, for example)
6789 //
6790 if (is_scalar($raw_value[0]))
6791 {
6792 $a_cleaned_values = CleanValue($raw_value);
6793 //
6794 // the output is a comma separated list of values for the
6795 // checkbox. For example,
6796 // events: Diving,Cycling,Running
6797 //
6798 // Set the clean value to the list of cleaned checkbox
6799 // values.
6800 // First, remove any commas in the values themselves.
6801 //
6802 $a_cleaned_values = str_replace(",","",$a_cleaned_values);
6803 $s_cleaned_value = implode(",",$a_cleaned_values);
6804 }
6805 else
6806 $s_cleaned_value = "<invalid list>";
6807 }
6808 else
6809 {
6810 //
6811 // NOTE: there is a minor bug here now that we support
6812 // $FORM_INI_FILE. The INI file is processed at the end
6813 // so if you set the mail_options below in the INI file they
6814 // won't get processed here. This means you must set
6815 // the following mail_options in the HTML form for now.
6816 // (To be fixed at a later date. RJR 17-Feb-06).
6817 //
6818
6819 //
6820 // if the form specifies the "KeepLines" option,
6821 // don't strip new lines
6822 //
6823 if (IsMailOptionSet("KeepLines") && strpos($raw_value,"\n") !== false)
6824 {
6825 //
6826 // truncate first
6827 //
6828 $s_truncated = substr("$raw_value",0,MAXSTRING);
6829 //
6830 // split into lines, clean each individual line,
6831 // then put it back together again
6832 //
6833 $a_lines = explode("\n",$s_truncated);
6834 $a_lines = CleanValue($a_lines);
6835 $s_cleaned_value = implode(BODY_LF,$a_lines);
6836 //
6837 // and, for this special case, prepend a new line
6838 // so that the value is shown on a fresh line
6839 //
6840 $s_cleaned_value = BODY_LF.$s_cleaned_value;
6841 }
6842 else
6843 $s_cleaned_value = CleanValue($raw_value);
6844 }
6845 //
6846 // if the form specifies the "NoEmpty" option, skip
6847 // empty values.
6848 //
6849 if (!IsMailOptionSet("NoEmpty") || !IsFieldEmpty($s_cleaned_value))
6850 if (!IsMailExcluded($s_name))
6851 {
6852 //
6853 // by default, we maintain the order as passed in
6854 // the HTTP request
6855 //
6856 $a_order[] = $s_name;
6857 $a_fields[$s_name] = $s_cleaned_value;
6858 }
6859
6860 //
6861 // add to the $FORMATTED_INPUT array for debugging and
6862 // error reporting
6863 //
6864 array_push($FORMATTED_INPUT,"$s_name: '$s_cleaned_value'");
6865 }
6866}
6867
6868 //
6869 // Parse the input variables and return:
6870 // 1. an array that specifies the required field order in the output
6871 // 2. an array containing the non-special cleaned field values indexed
6872 // by field name.
6873 // 3. an array containing the non-special raw field values indexed by
6874 // field name.
6875 //
6876function ParseInput($a_vars)
6877{
6878 $a_order = array();
6879 $a_fields = array();
6880 $a_raw_fields = array();
6881 //
6882 // scan the array of values passed in (name-value pairs) and
6883 // produce slightly formatted (not HTML) textual output
6884 // and extract any special values found.
6885 //
6886 foreach ($a_vars as $s_name=>$raw_value)
6887 ProcessField($s_name,$raw_value,$a_order,$a_fields,$a_raw_fields);
6888
6889 return (array($a_order,$a_fields,$a_raw_fields));
6890}
6891
6892 //
6893 // Get the URL for sending to the CRM.
6894 //
6895function GetCRMURL($spec,$vars,$url)
6896{
6897 $bad = false;
6898 $list = TrimArray(explode(",",$spec));
6899 $map = array();
6900 for ($ii = 0 ; $ii < count($list) ; $ii++)
6901 {
6902 $name = $list[$ii];
6903 if ($name)
6904 {
6905 //
6906 // the specification must be in this format:
6907 // form-field-name:CRM-field-name
6908 //
6909 if (($i_crm_name_pos = strpos($name,":")) > 0)
6910 {
6911 $s_crm_name = substr($name,$i_crm_name_pos + 1);
6912 $name = substr($name,0,$i_crm_name_pos);
6913 if (isset($vars[$name]))
6914 {
6915 $map[] = $s_crm_name."=".urlencode($vars[$name]);
6916 $map[] = "Orig_".$s_crm_name."=".urlencode($name);
6917 }
6918 }
6919 else
6920 {
6921 //
6922 // not the right format, so just include as a parameter
6923 // check for name=value format to choose encoding
6924 //
6925 $a_values = explode("=",$name);
6926 if (count($a_values) > 1)
6927 $map[] = urlencode($a_values[0])."=".urlencode($a_values[1]);
6928 else
6929 $map[] = urlencode($a_values[0]);
6930 }
6931 }
6932 }
6933 if (count($map) == 0)
6934 return ("");
6935 return (AddURLParams($url,$map,false));
6936}
6937
6938 //
6939 // strip the HTML from a string
6940 //
6941function StripHTML($s_str,$s_line_feed = "\n")
6942{
6943 //
6944 // strip HTML comments (s option means include new lines in matches)
6945 //
6946 $s_str = preg_replace('/<!--([^-]*([^-]|-([^-]|-[^>])))*-->/s','',$s_str);
6947 //
6948 // strip any scripts (i option means case-insensitive)
6949 //
6950 $s_str = preg_replace('/<script[^>]*?>.*?<\/script[^>]*?>/si','',$s_str);
6951 //
6952 // replace paragraphs with new lines (line feeds)
6953 //
6954 $s_str = preg_replace('/<p[^>]*?>/i',$s_line_feed,$s_str);
6955 //
6956 // replace breaks with new lines (line feeds)
6957 //
6958 $s_str = preg_replace('/<br[[:space:]]*\/?[[:space:]]*>/i',$s_line_feed,$s_str);
6959 //
6960 // overcome this bug: http://bugs.php.net/bug.php?id=21311
6961 //
6962 $s_str = preg_replace('/<![^>]*>/s','',$s_str);
6963 //
6964 // get rid of all HTML tags
6965 //
6966 $s_str = strip_tags($s_str);
6967 return ($s_str);
6968}
6969
6970 //
6971 // Check for valid URL in TARGET_URLS
6972 //
6973function CheckValidURL($s_url)
6974{
6975 global $TARGET_URLS;
6976
6977 foreach ($TARGET_URLS as $s_prefix)
6978 if (!empty($s_prefix) &&
6979 strtolower(substr($s_url,0,strlen($s_prefix))) ==
6980 strtolower($s_prefix))
6981 return (true);
6982 return (false);
6983}
6984
6985 //
6986 // Scan the given data for fields returned from the CRM.
6987 // A field has this following format:
6988 // __FIELDNAME__=value
6989 // terminated by a line feed.
6990 //
6991function FindCRMFields($s_data)
6992{
6993 $a_ret = array();
6994 if (preg_match_all('/^__([A-Za-z][A-Za-z0-9_]*)__=(.*)$/m',$s_data,$a_matches) === false)
6995 SendAlert(GetMessage(MSG_PREG_FAILED));
6996 else
6997 {
6998 $n_matches = count($a_matches[0]);
6999 // SendAlert("$n_matches on '$s_data'");
7000 for ($ii = 0 ; $ii < $n_matches ; $ii++)
7001 if (isset($a_matches[1][$ii]) && isset($a_matches[2][$ii]))
7002 $a_ret[$a_matches[1][$ii]] = $a_matches[2][$ii];
7003 }
7004 return ($a_ret);
7005}
7006
7007 //
7008 // open the given URL to send data to it, we expect the response
7009 // to contain at least '__OK__=' followed by true or false
7010 //
7011function SendToCRM($s_url,&$a_data)
7012{
7013 global $php_errormsg;
7014
7015 if (!CheckValidURL($s_url))
7016 {
7017 SendAlert(GetMessage(MSG_URL_INVALID,array("URL"=>$s_url)));
7018 return (false);
7019 }
7020@ $fp = fopen($s_url,"r");
7021 if ($fp === false)
7022 {
7023 SendAlert(GetMessage(MSG_URL_OPEN,array("URL"=>$s_url,
7024 "ERROR"=>CheckString($php_errormsg))));
7025 return (false);
7026 }
7027 $s_mesg = "";
7028 while (!feof($fp))
7029 {
7030 $s_line = fgets($fp,4096);
7031 $s_mesg .= $s_line;
7032 }
7033 fclose($fp);
7034 $s_mesg = StripHTML($s_mesg);
7035 $s_result = preg_match('/__OK__=(.*)/',$s_mesg,$a_matches);
7036 if (count($a_matches) < 2 || $a_matches[1] === "")
7037 {
7038 //
7039 // no agreed __OK__ value returned - assume system error
7040 //
7041 SendAlert(GetMessage(MSG_CRM_FAILED,array("URL"=>$s_url,
7042 "MSG"=>$s_mesg)));
7043 return (false);
7044 }
7045 //
7046 // look for fields to return
7047 //
7048 $a_data = FindCRMFields($s_mesg);
7049 //
7050 // check for success or user error
7051 //
7052 switch (strtolower($a_matches[1]))
7053 {
7054 case "true":
7055 break;
7056 case "false":
7057 //
7058 // user error
7059 //
7060 $s_error_code = "crm_error";
7061 $s_error_mesg = GetMessage(MSG_CRM_FORM_ERROR);
7062 if (isset($a_data["USERERRORCODE"]))
7063 $s_error_code .= $a_data["USERERRORCODE"];
7064 if (isset($a_data["USERERRORMESG"]))
7065 $s_error_mesg = $a_data["USERERRORMESG"];
7066 UserError($s_error_code,$s_error_mesg);
7067 // no return
7068 break;
7069 }
7070 return (true);
7071}
7072
7073 //
7074 // Split into field name and friendly name; returns an array with
7075 // two elements.
7076 // Format is:
7077 // fieldname:Nice printable name for displaying
7078 //
7079function GetFriendlyName($s_name)
7080{
7081 if (($i_pos = strpos($s_name,':')) === false)
7082 return (array(trim($s_name),trim($s_name)));
7083 return (array(trim(substr($s_name,0,$i_pos)),trim(substr($s_name,$i_pos+1))));
7084}
7085
7086define("REQUIREDOPS","|^!="); // operand characters for advanced required processing
7087
7088 //
7089 // Perform a field comparison test.
7090 //
7091function FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,&$s_error_mesg,
7092 $s_friendly1 = "",$s_friendly2 = "")
7093{
7094 $b_ok = true;
7095 //
7096 // perform the test
7097 //
7098 switch ($s_oper)
7099 {
7100 case '&': // both fields must be present
7101 if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) &&
7102 !TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
7103 ; // OK
7104 else
7105 {
7106 //
7107 // failed
7108 //
7109 $s_error_mesg = GetMessage(MSG_AND,array("ITEM1"=>$s_friendly1,
7110 "ITEM2"=>$s_friendly2));
7111 $b_ok = false;
7112 }
7113 break;
7114 case '|': // either field or both must be present
7115 if (!TestFieldEmpty($s_fld1,$a_vars,$s_empty1) ||
7116 !TestFieldEmpty($s_fld2,$a_vars,$s_empty2))
7117 ; // OK
7118 else
7119 {
7120 //
7121 // failed
7122 //
7123 $s_error_mesg = GetMessage(MSG_OR,array("ITEM1"=>$s_friendly1,
7124 "ITEM2"=>$s_friendly2));
7125 $b_ok = false;
7126 }
7127 break;
7128 case '^': // either field but not both must be present
7129 $b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
7130 $b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
7131 if ($b_got1 || $b_got2)
7132 {
7133 if ($b_got1 && $b_got2)
7134 {
7135 //
7136 // failed
7137 //
7138 $s_error_mesg = GetMessage(MSG_NOT_BOTH,
7139 array("ITEM1"=>$s_friendly1,
7140 "ITEM2"=>$s_friendly2));
7141 $b_ok = false;
7142 }
7143 }
7144 else
7145 {
7146 //
7147 // failed
7148 //
7149 $s_error_mesg = GetMessage(MSG_XOR,
7150 array("ITEM1"=>$s_friendly1,
7151 "ITEM2"=>$s_friendly2));
7152 $b_ok = false;
7153 }
7154 break;
7155 case '!=':
7156 case '=':
7157 $b_got1 = !TestFieldEmpty($s_fld1,$a_vars,$s_empty1);
7158 $b_got2 = !TestFieldEmpty($s_fld2,$a_vars,$s_empty2);
7159 if ($b_got1 && $b_got2)
7160 $b_match = (GetFieldValue($s_fld1,$a_vars) ==
7161 GetFieldValue($s_fld2,$a_vars));
7162 elseif (!$b_got1 && !$b_got2)
7163 //
7164 // haven't got either value - they match
7165 //
7166 $b_match = true;
7167 else
7168 //
7169 // got one value, but not the other - they don't match
7170 //
7171 $b_match = false;
7172 if ($s_oper != '=')
7173 {
7174 //
7175 // != operator
7176 //
7177 $b_match = !$b_match;
7178 $s_desc = GetMessage(MSG_IS_SAME_AS,
7179 array("ITEM1"=>$s_friendly1,
7180 "ITEM2"=>$s_friendly2));
7181 }
7182 else
7183 $s_desc = GetMessage(MSG_IS_NOT_SAME_AS,
7184 array("ITEM1"=>$s_friendly1,
7185 "ITEM2"=>$s_friendly2));
7186 if (!$b_match)
7187 {
7188 //
7189 // failed
7190 //
7191 $s_error_mesg = $s_desc;
7192 $b_ok = false;
7193 }
7194 break;
7195 }
7196 return ($b_ok);
7197}
7198
7199 //
7200 // Process advanced "required" conditionals
7201 //
7202function AdvancedRequired($s_cond,$i_span,$a_vars,&$s_missing,&$a_missing_list)
7203{
7204 $b_ok = true;
7205 //
7206 // get first field name
7207 //
7208 list($s_fld1,$s_friendly1) = GetFriendlyName(substr($s_cond,0,$i_span));
7209 //
7210 // get the operator
7211 //
7212 $s_rem = substr($s_cond,$i_span);
7213 $i_span = strspn($s_rem,REQUIREDOPS);
7214 $s_oper = substr($s_rem,0,$i_span);
7215 switch ($s_oper)
7216 {
7217 case '|':
7218 case '^':
7219 case '=':
7220 case '!=':
7221 //
7222 // second component is a field name
7223 //
7224 list($s_fld2,$s_friendly2) = GetFriendlyName(substr($s_rem,$i_span));
7225 if (!FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg,
7226 $s_friendly1,$s_friendly2))
7227 {
7228 //
7229 // failed
7230 //
7231 $s_missing .= "$s_error_mesg\n";
7232 $a_missing_list[] = "$s_error_mesg";
7233 $b_ok = false;
7234 }
7235 break;
7236 default:
7237 SendAlert(GetMessage(MSG_REQD_OPER,array("OPER"=>$s_oper)));
7238 break;
7239 }
7240 return ($b_ok);
7241}
7242
7243 //
7244 // Check the input for required values. The list of required fields
7245 // is a comma-separated list of field names or conditionals
7246 //
7247function CheckRequired($s_reqd,$a_vars,&$s_missing,&$a_missing_list)
7248{
7249 $b_bad = false;
7250 $a_list = TrimArray(explode(",",$s_reqd));
7251 $s_missing = "";
7252 $a_missing_list = array();
7253 for ($ii = 0 ; $ii < count($a_list) ; $ii++)
7254 {
7255 $s_cond = $a_list[$ii];
7256 $i_len = strlen($s_cond);
7257 if ($i_len <= 0)
7258 continue;
7259 if (($i_span = strcspn($s_cond,REQUIREDOPS)) >= $i_len)
7260 {
7261 //
7262 // no advanced operator; just a field name
7263 //
7264 list($s_fld,$s_friendly) = GetFriendlyName($s_cond);
7265 if (TestFieldEmpty($s_fld,$a_vars,$s_mesg))
7266 {
7267 if ($s_mesg === "")
7268 $s_mesg = "$s_friendly";
7269 else
7270 $s_mesg = "$s_friendly ($s_mesg)";
7271 $b_bad = true;
7272 $s_missing .= "$s_mesg\n";
7273 $a_missing_list[] = "$s_mesg";
7274 }
7275 }
7276 elseif (!AdvancedRequired($s_cond,$i_span,$a_vars,
7277 $s_missing,$a_missing_list))
7278 $b_bad = true;
7279 }
7280 return (!$b_bad);
7281}
7282
7283 //
7284 // Run a condition test
7285 //
7286function RunTest($s_test,$a_vars)
7287{
7288 global $aAlertInfo;
7289
7290 $s_op_chars = "&|^!=~#<>"; // these are the characters for the operators
7291 $i_len = strlen($s_test);
7292 $b_ok = true;
7293 if ($i_len <= 0)
7294 //
7295 // empty test - true
7296 //
7297 ;
7298 elseif ($s_test == "!")
7299 //
7300 // test asserts false
7301 //
7302 $b_ok = false;
7303 elseif (($i_span = strcspn($s_test,$s_op_chars)) >= $i_len)
7304 //
7305 // no operator - just check field presence
7306 //
7307 $b_ok = !TestFieldEmpty($s_test,$a_vars,$s_mesg);
7308 else
7309 {
7310 //
7311 // get first field name
7312 //
7313 $s_fld1 = trim(substr($s_test,0,$i_span));
7314 //
7315 // get the operator
7316 //
7317 $s_rem = substr($s_test,$i_span);
7318 $i_span = strspn($s_rem,$s_op_chars);
7319 $s_oper = substr($s_rem,0,$i_span);
7320 switch ($s_oper)
7321 {
7322 case '&':
7323 case '|':
7324 case '^':
7325 case '=':
7326 case '!=':
7327 //
7328 // get the second field name
7329 //
7330 $s_fld2 = trim(substr($s_rem,$i_span));
7331 $b_ok = FieldTest($s_oper,$s_fld1,$s_fld2,$a_vars,$s_error_mesg);
7332 break;
7333 case '~':
7334 case '!~':
7335 //
7336 // get the regular expression
7337 //
7338 $s_pat = trim(substr($s_rem,$i_span));
7339 if (!TestFieldEmpty($s_fld1,$a_vars,$s_mesg))
7340 $s_value = GetFieldValue($s_fld1,$a_vars);
7341 else
7342 $s_value = "";
7343 //echo "<p>Pattern: '".htmlspecialchars($s_pat)."': count=".preg_match($s_pat,$s_value)."<br /></p>";
7344 //
7345 // match the regular expression
7346 //
7347 if (preg_match($s_pat,$s_value) > 0)
7348 $b_ok = ($s_oper == '~');
7349 else
7350 $b_ok = ($s_oper == '!~');
7351 if (!$b_ok)
7352 $aAlertInfo[] = GetMessage(MSG_PAT_FAILED,array("OPER"=>$s_oper,
7353 "PAT"=>$s_pat,
7354 "VALUE"=>$s_value));
7355 break;
7356 case '#=':
7357 case '#!=':
7358 case '#<':
7359 case '#>':
7360 case '#<=':
7361 case '#>=':
7362 //
7363 // numeric tests
7364 //
7365 $s_num = trim(substr($s_rem,$i_span));
7366 //
7367 // if this is a file field, get the size of the file for
7368 // numeric tests
7369 //
7370 if (($s_value = GetFileSize($s_fld1)) === false)
7371 $s_value = $a_vars[$s_fld1];
7372 if (strpos($s_num,'.') === false)
7373 {
7374 //
7375 // treat as integer
7376 //
7377 $m_num = (int) $s_num;
7378 $m_fld = (int) $s_value;
7379 }
7380 else
7381 {
7382 //
7383 // treat as floating point
7384 //
7385 $m_num = (float) $s_num;
7386 $m_fld = (float) $s_value;
7387 }
7388 switch ($s_oper)
7389 {
7390 case '#=':
7391 $b_ok = ($m_fld == $m_num);
7392 break;
7393 case '#!=':
7394 $b_ok = ($m_fld != $m_num);
7395 break;
7396 case '#<':
7397 $b_ok = ($m_fld < $m_num);
7398 break;
7399 case '#>':
7400 $b_ok = ($m_fld > $m_num);
7401 break;
7402 case '#<=':
7403 $b_ok = ($m_fld <= $m_num);
7404 break;
7405 case '#>=':
7406 $b_ok = ($m_fld >= $m_num);
7407 break;
7408 }
7409 break;
7410 default:
7411 SendAlert(GetMessage(MSG_COND_OPER,array("OPER"=>$s_oper)));
7412 break;
7413 }
7414 }
7415 return ($b_ok);
7416}
7417
7418 //
7419 // Check the input for condition tests.
7420 //
7421function CheckConditions($m_conditions,$a_vars,&$s_missing,&$a_missing_list,$m_id = false)
7422{
7423 if (is_array($m_conditions))
7424 {
7425 //
7426 // Sort the conditions by their numeric value. This ensures
7427 // conditions are executed in the right order.
7428 //
7429 ksort($m_conditions,SORT_NUMERIC);
7430 foreach ($m_conditions as $m_key=>$s_cond)
7431 if (!CheckConditions($s_cond,$a_vars,$s_missing,$a_missing_list,$m_key))
7432 return (false);
7433 return (true);
7434 }
7435 $s_fld_name = "conditions".($m_id === false ? "" : ($m_id+1));
7436 if (!is_string($m_conditions))
7437 {
7438 SendAlert(GetMessage(MSG_INV_COND,array("FLD"=>$s_fld_name)));
7439 return (true); // pass invalid conditions
7440 }
7441 if ($m_conditions == "")
7442 return (true); // pass empty conditions
7443 $s_cond = $m_conditions;
7444 //
7445 // extract the separator characters
7446 //
7447 if (strlen($s_cond) < 2)
7448 {
7449 SendAlert(GetMessage(MSG_COND_CHARS,
7450 array("FLD"=>$s_fld_name,"COND"=>$s_cond)));
7451 return (true); // pass invalid conditions
7452 }
7453 $s_list_sep = $s_cond{0};
7454 $s_int_sep = $s_cond{1};
7455 $s_full_cond = $s_cond = substr($s_cond,2);
7456 $b_bad = false;
7457 $a_list = TrimArray(explode($s_list_sep,$s_cond));
7458 $s_missing = "";
7459 $a_missing_list = array();
7460 for ($ii = 0 ; $ii < count($a_list) ; $ii++)
7461 {
7462 $s_cond = $a_list[$ii];
7463 $i_len = strlen($s_cond);
7464 if ($i_len <= 0)
7465 continue;
7466 //
7467 // split the condition into its internal components
7468 //
7469 $a_components = TrimArray(explode($s_int_sep,$s_cond));
7470 if (count($a_components) < 5)
7471 {
7472 SendAlert(GetMessage(MSG_COND_INVALID,
7473 array("FLD"=>$s_fld_name,"COND"=>$s_cond,
7474 "SEP"=>$s_int_sep)));
7475 //
7476 // the smallest condition has 5 components
7477 //
7478 continue;
7479 }
7480 //
7481 // first component is ignored (it's blank)
7482 //
7483 $a_components = array_slice($a_components,1);
7484 switch ($a_components[0])
7485 {
7486 case "TEST":
7487 if (count($a_components) > 5)
7488 {
7489 SendAlert(GetMessage(MSG_COND_TEST_LONG,
7490 array("FLD"=>$s_fld_name,"COND"=>$s_cond,
7491 "SEP"=>$s_list_sep)));
7492 continue;
7493 }
7494 if (!RunTest($a_components[1],$a_vars))
7495 {
7496 $s_missing .= $a_components[2]."\n";
7497 $a_missing_list[] = $a_components[2];
7498 $b_bad = true;
7499 }
7500 break;
7501 case "IF":
7502 if (count($a_components) < 6)
7503 {
7504 SendAlert(GetMessage(MSG_COND_IF_SHORT,
7505 array("FLD"=>$s_fld_name,"COND"=>$s_cond,
7506 "SEP"=>$s_int_sep)));
7507 continue;
7508 }
7509 if (count($a_components) > 7)
7510 {
7511 SendAlert(GetMessage(MSG_COND_IF_LONG,
7512 array("FLD"=>$s_fld_name,"COND"=>$s_cond,
7513 "SEP"=>$s_list_sep)));
7514 continue;
7515 }
7516 if (RunTest($a_components[1],$a_vars))
7517 $b_test = RunTest($a_components[2],$a_vars);
7518 else
7519 $b_test = RunTest($a_components[3],$a_vars);
7520 if (!$b_test)
7521 {
7522 $s_missing .= $a_components[4]."\n";
7523 $a_missing_list[] = $a_components[4];
7524 $b_bad = true;
7525 }
7526 break;
7527 default:
7528 SendAlert(GetMessage(MSG_COND_UNK,
7529 array("FLD"=>$s_fld_name,"COND"=>$s_cond,
7530 "CMD"=>$a_components[0])));
7531 break;
7532 }
7533 }
7534 return (!$b_bad);
7535}
7536
7537 //
7538 // Return a formatted list of the given environment variables.
7539 //
7540function GetEnvVars($list,$s_line_feed)
7541{
7542 global $VALID_ENV,$aServerVars;
7543
7544 $output = "";
7545 for ($ii = 0 ; $ii < count($list) ; $ii++)
7546 {
7547 $name = $list[$ii];
7548 if ($name && array_search($name,$VALID_ENV,true) !== false)
7549 {
7550 //
7551 // if the environment variable is empty or non-existent, try
7552 // looking for the value in the server vars.
7553 //
7554 if (($s_value = getenv($name)) === "" || $s_value === false)
7555 if (isset($aServerVars[$name]))
7556 $s_value = $aServerVars[$name];
7557 else
7558 $s_value = "";
7559 $output .= $name."=".$s_value.$s_line_feed;
7560 }
7561 }
7562 return ($output);
7563}
7564 //
7565 // open a socket connection to a filter and post the data there
7566 //
7567function SocketFilter($filter,$a_filter_info,$m_data)
7568{
7569 static $b_in_here = false;
7570 global $php_errormsg;
7571
7572 //
7573 // prevent recursive errors
7574 //
7575 if ($b_in_here)
7576 return ("<DATA DISCARDED>");
7577 $b_in_here = true;
7578
7579 $a_errors = array();
7580 if (!isset($a_filter_info["site"]))
7581 $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"site"));
7582 else
7583 $s_site = $a_filter_info["site"];
7584
7585 if (!isset($a_filter_info["port"]))
7586 $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"port"));
7587 else
7588 $i_port = (int) $a_filter_info["port"];
7589
7590 if (!isset($a_filter_info["path"]))
7591 $a_errors[] = GetMessage(MSG_MISSING,array("ITEM"=>"path"));
7592 else
7593 $s_path = $a_filter_info["path"];
7594
7595 if (!isset($a_filter_info["params"]))
7596 $a_params = array();
7597 elseif (!is_array($a_filter_info["params"]))
7598 $a_errors[] = GetMessage(MSG_NEED_ARRAY,array("ITEM"=>"params"));
7599 else
7600 $a_params = $a_filter_info["params"];
7601
7602 if (!empty($a_errors))
7603 {
7604 Error("bad_filter",GetMessage(MSG_FILTER_WRONG,array(
7605 "FILTER"=>$filter,
7606 "ERRORS"=>implode(', ',$a_errors))),false,false);
7607 exit;
7608 }
7609
7610 //
7611 // ready to build the socket - we need a longer time limit for the
7612 // script if we're doing this; we allow 30 seconds for the connection
7613 // (should be instantaneous, especially if it's the same domain)
7614 //
7615 set_time_limit(60);
7616@ $f_sock = fsockopen($s_site,$i_port,$i_errno,$s_errstr,30);
7617 if ($f_sock === false)
7618 {
7619 Error("filter_connect",GetMessage(MSG_FILTER_CONNECT,array(
7620 "FILTER"=>$filter,
7621 "SITE"=>$s_site,
7622 "ERRNUM"=>$i_errno,
7623 "ERRSTR"=>"$s_errstr (".CheckString($php_errormsg).")")),
7624 false,false);
7625 exit;
7626 }
7627 //
7628 // build the data to send
7629 //
7630 $m_request_data = array();
7631 $i_count = 0;
7632 foreach ($a_params as $m_var)
7633 {
7634 $i_count++;
7635 //
7636 // if the parameter spec is an array, process it specially;
7637 // it must have "name" and "file" elements
7638 //
7639 if (is_array($m_var))
7640 {
7641 if (!isset($m_var["name"]))
7642 {
7643 Error("bad_filter",GetMessage(MSG_FILTER_PARAM,
7644 array("FILTER"=>$filter,
7645 "NUM"=>$i_count,
7646 "NAME"=>"name")),false,false);
7647 fclose($f_sock);
7648 exit;
7649 }
7650 $s_name = $m_var["name"];
7651 if (!isset($m_var["file"]))
7652 {
7653 Error("bad_filter",GetMessage(MSG_FILTER_PARAM,
7654 array("FILTER"=>$filter,
7655 "NUM"=>$i_count,
7656 "NAME"=>"file")),false,false);
7657 fclose($f_sock);
7658 exit;
7659 }
7660 //
7661 // open the file and read its contents
7662 //
7663@ $fp = fopen($m_var["file"],"r");
7664 if ($fp === false)
7665 {
7666 Error("filter_error",GetMessage(MSG_FILTER_OPEN_FILE,
7667 array("FILTER"=>$filter,
7668 "FILE"=>$m_var["file"],
7669 "ERROR"=>CheckString($php_errormsg))),false,false);
7670 fclose($f_sock);
7671 exit;
7672 }
7673 $s_data = "";
7674 $n_lines = 0;
7675 while (!feof($fp))
7676 {
7677 if (($s_line = fgets($fp,2048)) === false)
7678 if (feof($fp))
7679 break;
7680 else
7681 {
7682 Error("filter_error",GetMessage(MSG_FILTER_FILE_ERROR,
7683 array("FILTER"=>$filter,
7684 "FILE"=>$m_var["file"],
7685 "ERROR"=>CheckString($php_errormsg),
7686 "NLINES"=>$n_lines)),false,false);
7687 fclose($f_sock);
7688 exit;
7689 }
7690 $s_data .= $s_line;
7691 $n_lines++;
7692 }
7693
7694 fclose($fp);
7695 $m_request_data[] = "$s_name=".urlencode($s_data);
7696 }
7697 else
7698 $m_request_data[] = (string) $m_var;
7699 }
7700 //
7701 // add the data
7702 //
7703 if (is_array($m_data))
7704 $m_request_data[] = "data=".urlencode(implode(BODY_LF,$m_data));
7705 else
7706 $m_request_data[] = "data=".urlencode($m_data);
7707 $s_request = implode("&",$m_request_data);
7708
7709 if (($i_pos = strpos($s_site,"://")) !== false)
7710 $s_site_name = substr($s_site,$i_pos+3);
7711 else
7712 $s_site_name = $s_site;
7713
7714 fputs($f_sock,"POST $s_path HTTP/1.0\r\n");
7715 fputs($f_sock,"Host: $s_site_name\r\n");
7716 fputs($f_sock,"Content-Type: application/x-www-form-urlencoded\r\n");
7717 fputs($f_sock,"Content-Length: ".strlen($s_request)."\r\n");
7718 fputs($f_sock,"\r\n");
7719 fputs($f_sock,"$s_request\r\n");
7720
7721 //
7722 // now read the response
7723 //
7724 $m_hdr = "";
7725 $m_data = "";
7726 $b_in_hdr = true;
7727 $b_ok = false;
7728 while (!feof($f_sock))
7729 {
7730 if (($s_line = fgets($f_sock,2048)) === false)
7731 if (feof($f_sock))
7732 break;
7733 else
7734 {
7735 Error("filter_failed",GetMessage(MSG_FILTER_READ_ERROR,
7736 array("FILTER"=>$filter,
7737 "ERROR"=>CheckString($php_errormsg))),false,false);
7738 fclose($f_sock);
7739 exit;
7740 }
7741 //
7742 // look for an "__OK__" line
7743 //
7744 if (trim($s_line) == "__OK__")
7745 $b_ok = true;
7746 elseif ($b_in_hdr)
7747 {
7748 //
7749 // blank line signals end of header
7750 //
7751 if (trim($s_line) == "")
7752 $b_in_hdr = false;
7753 else
7754 $m_hdr .= $s_line;
7755 }
7756 else
7757 $m_data .= $s_line;
7758 }
7759 //
7760 // if not OK, then report error
7761 //
7762 if (!$b_ok)
7763 {
7764 Error("filter_failed",GetMessage(MSG_FILTER_NOT_OK,
7765 array("FILTER"=>$filter,
7766 "DATA"=>$m_data)),false,false);
7767 fclose($f_sock);
7768 exit;
7769 }
7770 fclose($f_sock);
7771 $b_in_here = false;
7772 return ($m_data);
7773}
7774
7775 //
7776 // run data through a supported filter
7777 //
7778function Filter($filter,$m_data)
7779{
7780 global $FILTERS,$SOCKET_FILTERS;
7781 static $b_in_here = false;
7782
7783 //
7784 // prevent recursive errors
7785 //
7786 if ($b_in_here)
7787 return ("<DATA DISCARDED>");
7788 $b_in_here = true;
7789
7790 //
7791 // Any errors sent in an alert are flagged to not run through the
7792 // filter - this also means the user's data won't be included in the
7793 // alert.
7794 // The reason for this is that the Filter is typically an encryption
7795 // program. If the filter fails, then sending the user's data in
7796 // clear text in an alert breaks the security of having encryption
7797 // in the first place!
7798 //
7799
7800 //
7801 // find the filter
7802 //
7803 if (!isset($FILTERS[$filter]) || $FILTERS[$filter] == "")
7804 {
7805 //
7806 // check for SOCKET_FILTERS
7807 //
7808 if (!isset($SOCKET_FILTERS[$filter]) || $SOCKET_FILTERS[$filter] == "")
7809 {
7810 Error("bad_filter",GetMessage(MSG_FILTER_UNK,
7811 array("FILTER"=>$filter)),false,false);
7812 exit;
7813 }
7814 $m_data = SocketFilter($filter,$SOCKET_FILTERS[$filter],$m_data);
7815 }
7816 elseif ($FILTERS[$filter] == "null")
7817 //
7818 // do nothing - just return the original data unchanged
7819 //
7820 ;
7821 else
7822 {
7823 $cmd = $FILTERS[$filter];
7824 //
7825 // get the program name - assumed to be the first blank-separated word
7826 //
7827 $a_words = preg_split('/\s+/',$cmd);
7828 $prog = $a_words[0];
7829
7830 $s_cwd = getcwd();
7831 //
7832 // change to the directory that contains the filter program
7833 //
7834 $dirname = dirname($prog);
7835 if ($dirname != "" && $dirname != "." && !chdir($dirname))
7836 {
7837 Error("chdir_filter",GetMessage(MSG_FILTER_CHDIR,
7838 array("DIR"=>$dirname,"FILTER"=>$filter,
7839 "ERROR"=>CheckString($php_errormsg))),false,false);
7840 exit;
7841 }
7842
7843 //
7844 // the output of the filter goes to a temporary file; this works
7845 // OK on Windows too, even with the Unix shell syntax.
7846 //
7847 $temp_file = GetTempName("FMF");
7848 $cmd = "$cmd > $temp_file 2>&1";
7849 //
7850 // start the filter
7851 //
7852 $pipe = popen($cmd,"w");
7853 if ($pipe === false)
7854 {
7855 $s_sv_err = CheckString($php_errormsg);
7856 $err = join('',file($temp_file));
7857 unlink($temp_file);
7858 Error("filter_not_found",GetMessage(MSG_FILTER_NOTFOUND,
7859 array("CMD"=>$cmd,"FILTER"=>$filter,
7860 "ERROR"=>$s_sv_err)),false,false,$err);
7861 exit;
7862 }
7863 //
7864 // write the data to the filter
7865 //
7866 if (is_array($m_data))
7867 fwrite($pipe,implode(BODY_LF,$m_data));
7868 else
7869 fwrite($pipe,$m_data);
7870 if (($i_st = pclose($pipe)) != 0)
7871 {
7872 $s_sv_err = CheckString($php_errormsg);
7873 $err = join('',file($temp_file));
7874 unlink($temp_file);
7875 Error("filter_failed",GetMessage(MSG_FILTER_ERROR,
7876 array("FILTER"=>$filter,
7877 "ERROR"=>$s_sv_err,
7878 "STATUS"=>$i_st)),false,false,$err);
7879 exit;
7880 }
7881 //
7882 // read in the filter's output and return as the data to be sent
7883 //
7884 $m_data = join('',file($temp_file));
7885 unlink($temp_file);
7886
7887 //
7888 // return to previous directory
7889 //
7890 chdir($s_cwd);
7891 }
7892 $b_in_here = false;
7893 return ($m_data);
7894}
7895
7896$aSubstituteErrors = array();
7897$aSubstituteValues = NULL;
7898$sSubstituteMissing = NULL;
7899
7900 //
7901 // Run htmlspecialchars on every value in an array.
7902 //
7903function ArrayHTMLSpecialChars($a_list)
7904{
7905 $a_new = array();
7906 foreach ($a_list as $m_key=>$m_value)
7907 if (is_array($m_value))
7908 $a_new[$m_key] = ArrayHTMLSpecialChars($m_value);
7909 else
7910 $a_new[$m_key] = htmlspecialchars($m_value);
7911 return ($a_new);
7912}
7913
7914 //
7915 // Worker function for SubstituteValue and SubstituteValueForPage.
7916 // Returns the value of the matched variable name.
7917 // Variables are searched for in the global $aSubstituteValues.
7918 // If no such variable exists, an error is reported or the given
7919 // replacement string is used.
7920 // Errors are stored in the global $aSubstituteErrors.
7921 //
7922function SubstituteValueWorker($a_matches,$s_repl,$b_html = true)
7923{
7924 global $aSubstituteErrors,$aSubstituteValues,$SPECIAL_VALUES;
7925
7926 $s_name = $a_matches[1];
7927 $s_value = "";
7928 if (IsFieldSet($s_name,$aSubstituteValues) &&
7929 !TestFieldEmpty($s_name,$aSubstituteValues,$s_mesg))
7930 {
7931 if (is_array($aSubstituteValues[$s_name]))
7932 //
7933 // note that the separator can include HTML special chars
7934 //
7935 $s_value = implode($SPECIAL_VALUES['template_list_sep'],
7936 $b_html ?
7937 ArrayHTMLSpecialChars($aSubstituteValues[$s_name]) :
7938 $aSubstituteValues[$s_name]);
7939 else
7940 {
7941 $s_value = GetFieldValue($s_name,$aSubstituteValues);
7942 if ($b_html)
7943 $s_value = htmlspecialchars($s_value);
7944 }
7945 if ($b_html)
7946 //
7947 // Replace newlines with HTML line breaks.
7948 //
7949 $s_value = nl2br($s_value);
7950 }
7951 elseif (isset($SPECIAL_VALUES[$s_name]))
7952 $s_value = $b_html ?
7953 htmlspecialchars((string) $SPECIAL_VALUES[$s_name]) :
7954 (string) $SPECIAL_VALUES[$s_name];
7955 elseif (isset($s_repl))
7956 //
7957 // If a replacement value has been specified use it, and
7958 // don't call htmlspecialchars. This allows the use
7959 // of HTML tags in a replacement string.
7960 //
7961 $s_value = $s_repl;
7962 else
7963 $aSubstituteErrors[] = GetMessage(MSG_FLD_NOTFOUND,array("FIELD"=>$s_name));
7964 return ($s_value);
7965}
7966
7967 //
7968 // Callback function for preg_replace_callback. Returns the value
7969 // of the matched variable name.
7970 // Variables are searched for in the global $aSubstituteValues.
7971 // If no such variable exists, an error is reported or an special
7972 // replacement string is used.
7973 // Errors are stored in the global $aSubstituteErrors.
7974 //
7975function SubstituteValue($a_matches)
7976{
7977 global $sSubstituteMissing;
7978
7979 return (SubstituteValueWorker($a_matches,$sSubstituteMissing));
7980}
7981
7982 //
7983 // Callback function for preg_replace_callback. Returns the value
7984 // of the matched variable name.
7985 // Variables are searched for in the global $aSubstituteValues.
7986 // If no such variable exists, an error is reported or an special
7987 // replacement string is used.
7988 // Errors are stored in the global $aSubstituteErrors.
7989 //
7990function SubstituteValuePlain($a_matches)
7991{
7992 global $sSubstituteMissing;
7993
7994 return (SubstituteValueWorker($a_matches,$sSubstituteMissing,false));
7995}
7996
7997 //
7998 // Callback function for preg_replace_callback. Returns the value
7999 // of the matched variable name.
8000 // Variables are searched for in the global $aSubstituteValues.
8001 // If no such variable exists, the empty string is substituted.
8002 // Errors are stored in the global $aSubstituteErrors.
8003 //
8004function SubstituteValueForPage($a_matches)
8005{
8006 return (SubstituteValueWorker($a_matches,""));
8007}
8008
8009 //
8010 // Process the given HTML template and fill the fields.
8011 //
8012function DoProcessTemplate($s_dir,$s_url,$s_template,&$a_lines,
8013 $a_values,$s_missing,$s_subs_func)
8014{
8015 global $aSubstituteErrors,$aSubstituteValues,$sSubstituteMissing;
8016
8017 if (($a_template_lines = LoadTemplate($s_template,$s_dir,
8018 $s_url,true)) === false)
8019 return (false);
8020
8021 $b_ok = true;
8022 //
8023 // initialize the errors list
8024 //
8025 $aSubstituteErrors = array();
8026 //
8027 // initialize the values
8028 //
8029 $aSubstituteValues = $a_values;
8030 $sSubstituteMissing = $s_missing;
8031
8032 foreach ($a_template_lines as $s_line)
8033 {
8034 //
8035 // search for words in this form:
8036 // $word
8037 // where word begins with an alphabetic character and
8038 // consists of alphanumeric and underscore
8039 //
8040 $a_lines[] = preg_replace_callback('/\$([a-z][a-z0-9_]*)/i',
8041 $s_subs_func,$s_line);
8042 }
8043
8044// SendAlert("Error count=".count($aSubstituteErrors));
8045 if (count($aSubstituteErrors) != 0)
8046 {
8047 SendAlert(GetMessage(MSG_TEMPLATE_ERRORS,array("NAME"=>$s_template)).
8048 implode("\n",$aSubstituteErrors));
8049 $b_ok = false;
8050 }
8051
8052 return ($b_ok);
8053}
8054
8055 //
8056 // Process the given HTML template and fill the fields.
8057 //
8058function ProcessTemplate($s_template,&$a_lines,$a_values,$s_missing = NULL,
8059 $s_subs_func = 'SubstituteValue')
8060{
8061 global $TEMPLATEURL,$TEMPLATEDIR;
8062
8063 if (empty($TEMPLATEDIR) && empty($TEMPLATEURL))
8064 {
8065 SendAlert(GetMessage(MSG_TEMPLATES));
8066 return (false);
8067 }
8068 return (DoProcessTemplate($TEMPLATEDIR,$TEMPLATEURL,$s_template,$a_lines,
8069 $a_values,$s_missing,$s_subs_func));
8070}
8071
8072 //
8073 // Output the given HTML template after filling in the fields.
8074 //
8075function OutputTemplate($s_template,$a_values)
8076{
8077 $a_lines = array();
8078 if (!ProcessTemplate($s_template,$a_lines,$a_values,"",'SubstituteValueForPage'))
8079 Error("template_failed",GetMessage(MSG_TEMPLATE_FAILED,
8080 array("NAME"=>$s_template)),false,false);
8081 else
8082 {
8083 for ($ii = 0 ; $ii < count($a_lines) ; $ii++)
8084 echo $a_lines[$ii]."\n";
8085 }
8086}
8087
8088 //
8089 // This function handles input type "text" and "password"
8090 //
8091function FixInputText($s_name,$s_value,$s_buf)
8092{
8093 //
8094 // we search for:
8095 // <input type="text" name="thename"...
8096 // and change it to:
8097 // <input type="text" name="thename" value="thevalue" ...
8098 //
8099 // Note that the value attribute must appear *after* the
8100 // type and name attributes.
8101 //
8102
8103 //
8104 // first strip any current value attribute for the field
8105 //
8106
8107 //
8108 // (?:) is a grouping subpattern that does no capturing
8109 //
8110
8111 // handle type attribute first
8112 $s_pat = '/(<\s*input[^>]*type="(?:text|password)"[^>]*name="';
8113 $s_pat .= preg_quote($s_name,"/");
8114 $s_pat .= '"[^>]*)(value="[^"]*")([^>]*?)(\s*\/\s*)?>';
8115 $s_pat .= '/ims';
8116 $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
8117
8118 // handle name attribute first
8119 $s_pat = '/(<\s*input[^>]*name="';
8120 $s_pat .= preg_quote($s_name,"/");
8121 $s_pat .= '"[^>]*type="(?:text|password)"[^>]*)(value="[^"]*")([^>]*?)(\s*\/\s*)?>';
8122 $s_pat .= '/ims';
8123 $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
8124
8125 //
8126 // now add in the new value
8127 //
8128 $s_repl = '$1 value="'.htmlspecialchars($s_value).'" $2>';
8129
8130 // handle type attribute first
8131 $s_pat = '/(<\s*input[^>]*type="(?:text|password)"[^>]*name="';
8132 $s_pat .= preg_quote($s_name,"/");
8133 $s_pat .= '"[^>]*?)(\s*\/\s*)?>';
8134 $s_pat .= '/ims';
8135 $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
8136
8137 // handle name attribute first
8138 $s_pat = '/(<\s*input[^>]*name="';
8139 $s_pat .= preg_quote($s_name,"/");
8140 $s_pat .= '"[^>]*type="(?:text|password)"[^>]*?)(\s*\/\s*)?>';
8141 $s_pat .= '/ims';
8142 $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
8143
8144 return ($s_buf);
8145}
8146
8147 //
8148 // This function handles textareas.
8149 //
8150function FixTextArea($s_name,$s_value,$s_buf)
8151{
8152 //
8153 // we search for:
8154 // <textarea name="thename"...>value</textarea>
8155 // and change it to:
8156 // <textarea name="thename"...>new value</textarea>
8157 //
8158
8159 $s_pat = '/(<\s*textarea[^>]*name="';
8160 $s_pat .= preg_quote($s_name,"/");
8161 $s_pat .= '"[^>]*)>.*?<\s*\/\s*textarea\s*>';
8162 $s_pat .= '/ims';
8163 //
8164 // we exclude the closing '>' from the match above so that
8165 // we can put it below. We need to do this so that the replacement
8166 // string is not faulty if the value begins with a digit:
8167 // $19 Some Street
8168 //
8169 $s_repl = '$1>'.htmlspecialchars($s_value).'</textarea>';
8170 $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
8171
8172 return ($s_buf);
8173}
8174
8175 //
8176 // This function handles radio buttons and non-array checkboxes.
8177 //
8178function FixButton($s_name,$s_value,$s_buf)
8179{
8180 //
8181 // we search for:
8182 // <input type="radio" name="thename" value="thevalue" ...
8183 // and change it to:
8184 // <input type="radio" name="thename" value="thevalue" checked="checked"
8185 //
8186 // Note that the value attribute must appear *after* the
8187 // type and name attributes.
8188 //
8189
8190 //
8191 // first strip any current checked attributes
8192 //
8193
8194 //
8195 // (?:) is a grouping subpattern that does no capturing
8196 //
8197
8198 // handle type attribute first
8199 // match: input tag with type 'radio' or 'checkbox' with attribute
8200 // 'checked' or 'checked="checked"'
8201 // <A NAME="PatternInfo">
8202 // [^>]*?[^"\w] matches up to a word boundary starting with
8203 // 'checked' but not '"checked'
8204 // (="checked"|(?=[^"\w]))? this matches:
8205 // nothing
8206 // ="checked"
8207 // any character except a word character or " (without
8208 // consuming it)
8209 //
8210 $s_pat = '/(<\s*input[^>]*type="(?:radio|checkbox)"[^>]*name="';
8211 $s_pat .= preg_quote($s_name,"/");
8212 $s_pat .= '"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
8213 $s_pat .= '/ims';
8214 $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
8215
8216 // handle name attribute first
8217 $s_pat = '/(<\s*input[^>]*name="';
8218 $s_pat .= preg_quote($s_name,"/");
8219 $s_pat .= '"[^>]*type="(?:radio|checkbox)"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
8220 $s_pat .= '/ims';
8221 $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
8222
8223 // handle type attribute first
8224 $s_pat = '/(<\s*input[^>]*type="(?:radio|checkbox)"[^>]*name="';
8225 $s_pat .= preg_quote($s_name,"/");
8226 $s_pat .= '"[^>]*value="';
8227 $s_pat .= preg_quote($s_value,"/");
8228 $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
8229 $s_pat .= '/ims';
8230 $s_buf = preg_replace($s_pat,'$1$2 checked="checked" $3>',$s_buf);
8231
8232 // handle name attribute first
8233 $s_pat = '/(<\s*input[^>]*name="';
8234 $s_pat .= preg_quote($s_name,"/");
8235 $s_pat .= '"[^>]*type="(?:radio|checkbox)"[^>]*value="';
8236 $s_pat .= preg_quote($s_value,"/");
8237 $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
8238 $s_pat .= '/ims';
8239 $s_buf = preg_replace($s_pat,'$1$2 checked="checked" $3>',$s_buf);
8240
8241 return ($s_buf);
8242}
8243
8244 //
8245 // This function handles checkboxes as an array of values.
8246 //
8247function FixCheckboxes($s_name,$a_values,$s_buf)
8248{
8249 //global $aDebug;
8250
8251 //
8252 // we search for:
8253 // <input type="checkbox" name="thename" value="thevalue" ...
8254 // and change it to:
8255 // <input type="checkbox" name="thename" value="thevalue" checked
8256 //
8257 // Note that the value attribute must appear *after* the
8258 // type and name attributes.
8259 //
8260
8261 //
8262 // first strip any current checked attributes
8263 //
8264 //$aDebug[] = "FixCheckboxes: Name='$s_name'";
8265
8266 // handle type attribute first
8267 // see <A HREF="fmbadhandler.php#PatternInfo">
8268 $s_pat = '/(<\s*input[^>]*type="checkbox"[^>]*name="';
8269 $s_pat .= preg_quote($s_name,"/");
8270 $s_pat .= '\[]"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
8271 $s_pat .= '/ims';
8272 $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
8273
8274 // handle name attribute first
8275 $s_pat = '/(<\s*input[^>]*name="';
8276 $s_pat .= preg_quote($s_name,"/");
8277 $s_pat .= '\[]"[^>]*type="checkbox"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
8278 $s_pat .= '/ims';
8279 $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
8280
8281 foreach ($a_values as $s_value)
8282 {
8283 // handle type attribute first
8284 $s_pat = '/(<\s*input[^>]*type="checkbox"[^>]*name="';
8285 $s_pat .= preg_quote($s_name,"/");
8286 $s_pat .= '\[\]"[^>]*value="';
8287 $s_pat .= preg_quote($s_value,"/");
8288 $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
8289 $s_pat .= '/ims';
8290 $s_buf = preg_replace($s_pat,'$1$2 checked="checked"$3>',$s_buf);
8291 //$aDebug[] = "Name='$s_name', pat='$s_pat'";
8292
8293 // handle name attribute first
8294 $s_pat = '/(<\s*input[^>]*name="';
8295 $s_pat .= preg_quote($s_name,"/");
8296 $s_pat .= '\[\]"[^>]*type="checkbox"[^>]*value="';
8297 $s_pat .= preg_quote($s_value,"/");
8298 $s_pat .= '")([^>]*?)(\s*\/\s*)?>';
8299 $s_pat .= '/ims';
8300 $s_buf = preg_replace($s_pat,'$1$2 checked="checked">',$s_buf);
8301 }
8302 return ($s_buf);
8303}
8304
8305 //
8306 // This function handles selects.
8307 //
8308function FixSelect($s_name,$s_value,$s_buf)
8309{
8310 //
8311 // we search for:
8312 // <select name="thename"...>
8313 // <option value="thevalue">...</option>
8314 // </select>
8315 //
8316
8317 $s_pat = '/(<\s*select[^>]*name="';
8318 $s_pat .= preg_quote($s_name,"/");
8319 $s_pat .= '".*?<\s*option[^>]*value="';
8320 $s_pat .= preg_quote($s_value,"/");
8321 $s_pat .= '"[^>]*)>';
8322 $s_pat .= '/ims';
8323 $s_repl = '$1 selected="selected">';
8324// echo "<p>pat: ".htmlspecialchars($s_pat);
8325 $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
8326
8327 return ($s_buf);
8328}
8329
8330 //
8331 // This function handles multiple selects.
8332 //
8333function FixMultiSelect($s_name,$a_values,$s_buf)
8334{
8335 //
8336 // we search for:
8337 // <select name="thename"...>
8338 // <option value="thevalue">...</option>
8339 // </select>
8340 //
8341
8342 foreach ($a_values as $s_value)
8343 {
8344 $s_pat = '/(<\s*select[^>]*name="';
8345 $s_pat .= preg_quote($s_name,"/");
8346 $s_pat .= '\[\]".*?<\s*option[^>]*value="';
8347 $s_pat .= preg_quote($s_value,"/");
8348 $s_pat .= '"[^>]*)>';
8349 $s_pat .= '/ims';
8350 $s_repl = '$1 selected="selected">';
8351 // echo "<p>pat: ".htmlspecialchars($s_pat);
8352 $s_buf = preg_replace($s_pat,$s_repl,$s_buf);
8353 }
8354 return ($s_buf);
8355}
8356
8357 //
8358 // This function unchecks all checkboxes and select options.
8359 //
8360function UnCheckStuff($s_buf)
8361{
8362 global $php_errormsg;
8363
8364 //
8365 // we search for:
8366 // <input type="checkbox" ... checked
8367 // and remove "checked" (checked="checked" is OK too)
8368 //
8369 // Note that the check attribute must appear *after* the
8370 // type attribute.
8371 // see <A HREF="fmbadhandler.php#PatternInfo">
8372 //
8373
8374 $s_pat = '/(<\s*input[^>]*type="checkbox"[^>]*?[^"\w])checked(="checked"|(?=[^"\w]))?([^>]*?)(\s*\/\s*)?>';
8375 $s_pat .= '/ims';
8376 $s_buf = preg_replace($s_pat,'$1$3$4>',$s_buf);
8377
8378 //
8379 // we search for:
8380 // <option... selected
8381 // and remove "selected" (selected="selected" is OK too)
8382 // see <A HREF="fmbadhandler.php#PatternInfo">
8383 //
8384
8385 $s_pat = '/(<\s*option[^>]*?[^"\w])selected(="selected"|(?=[^"\w]))?([^>]*)>';
8386 $s_pat .= '/ims';
8387 $s_buf = preg_replace($s_pat,'$1$3>',$s_buf);
8388
8389 return ($s_buf);
8390}
8391
8392 //
8393 // Add the user agent to the url as a parameter called USER_AGENT.
8394 // This allows dynamic web sites to know what the user's browser is.
8395 //
8396function AddUserAgent($s_url)
8397{
8398 global $aServerVars;
8399
8400 //
8401 // check for ? in the name
8402 //
8403 $b_quest = (strpos($s_url,'?') !== false);
8404 unset($s_agent);
8405 if (isset($aServerVars['HTTP_USER_AGENT']))
8406 $s_agent = $aServerVars['HTTP_USER_AGENT'];
8407 if (isset($s_agent))
8408 $s_url .= ($b_quest ? '&' : '?')."USER_AGENT=".urlencode($s_agent);
8409 return ($s_url);
8410}
8411
8412 //
8413 // Sets previous values in a form.
8414 //
8415function SetPreviousValues($s_form_buf,$a_values)
8416{
8417 //
8418 // Uncheck any checkboxes and select options
8419 //
8420 $s_form_buf = UnCheckStuff($s_form_buf);
8421 foreach ($a_values as $s_name=>$m_value)
8422 {
8423 if (is_array($m_value))
8424 {
8425 //
8426 // note that if no values are selected for a field,
8427 // then we will never get here for that field
8428 //
8429 $s_form_buf = FixCheckboxes($s_name,$m_value,$s_form_buf);
8430 $s_form_buf = FixMultiSelect($s_name,$m_value,$s_form_buf);
8431 }
8432 else
8433 {
8434 //
8435 // Fix the field if it's an input type "text" or "password".
8436 //
8437 $s_form_buf = FixInputText($s_name,$m_value,$s_form_buf);
8438 //
8439 // Fix the field if it's radio button.
8440 //
8441 $s_form_buf = FixButton($s_name,$m_value,$s_form_buf);
8442 //
8443 // Fix the field if it's a "textarea".
8444 //
8445 $s_form_buf = FixTextArea($s_name,$m_value,$s_form_buf);
8446 //
8447 // Fix the field if it's a "select".
8448 //
8449 $s_form_buf = FixSelect($s_name,$m_value,$s_form_buf);
8450 }
8451 }
8452 return ($s_form_buf);
8453}
8454
8455 //
8456 // Open a URL, do value substitutions, and send to browser.
8457 //
8458function ProcessReturnToForm($s_url,$a_values)
8459{
8460 global $aSubstituteErrors,$aSubstituteValues,$sSubstituteMissing;
8461 global $php_errormsg;
8462
8463 //
8464 // read the original form, and modify it to provide values
8465 // for the fields
8466 //
8467 if (!CheckValidURL($s_url))
8468 Error("invalid_url",GetMessage(MSG_RETURN_URL_INVALID,
8469 array("URL"=>$s_url)),false,false);
8470
8471 $s_form_url = AddUserAgent($s_url);
8472 $s_error = "";
8473 $s_form_buf = GetURL($s_form_url,$s_error);
8474 if ($s_form_buf === false)
8475 Error("invalid_url",GetMessage(MSG_OPEN_URL,
8476 array("URL"=>$s_form_url,
8477 "ERROR"=>$s_error.": ".(isset($php_errormsg) ?
8478 $php_errormsg : ""))),false,false);
8479
8480 /*****
8481 This is not correct here, because this function is only called
8482 for non-template URLs.
8483 //
8484 // First, we do any "$var" substitutions
8485 //
8486
8487 //
8488 // initialize the errors list
8489 //
8490 $aSubstituteErrors = array();
8491 //
8492 // initialize the values
8493 //
8494 $aSubstituteValues = $a_values;
8495 $sSubstituteMissing = $s_missing;
8496
8497 //
8498 // search for words in this form:
8499 // $word
8500 // where word begins with an alphabetic character and
8501 // consists of alphanumeric and underscore
8502 //
8503// $s_form_buf = preg_replace_callback('/\$([a-z][a-z0-9_]*)/i',
8504// 'SubstituteValueForPage',$s_form_buf);
8505
8506// SendAlert("Error count=".count($aSubstituteErrors));
8507 if (count($aSubstituteErrors) != 0)
8508 Error("template_failed",
8509 GetMessage(MSG_TEMPLATE_ERRORS,array("NAME"=>$s_template)).
8510 implode("\n",$aSubstituteErrors),false,false);
8511 ******/
8512
8513 //
8514 // Next, we replace or set actual field values.
8515 //
8516 echo SetPreviousValues($s_form_buf,$a_values);
8517}
8518
8519 //
8520 // To return the URL for returning to a particular multi-page form URL.
8521 //
8522function GetReturnLink($s_this_script,$i_form_index)
8523{
8524 if (!CheckValidURL($s_this_script))
8525 Error("not_valid_url",GetMessage(MSG_RETURN_URL_INVALID,
8526 array("URL"=>$s_this_script)),false,false);
8527
8528 $a_params = array();
8529 $a_params[] = "return=$i_form_index";
8530 if (isset($aServerVars["QUERY_STRING"]))
8531 $a_params[] = $aServerVars["QUERY_STRING"];
8532 $a_params[] = session_name()."=".session_id();
8533 return (AddURLParams($s_this_script,$a_params));
8534}
8535
8536 //
8537 // Process a multi-page form template.
8538 //
8539function ProcessMultiFormTemplate($s_template,$a_values,&$a_lines)
8540{
8541 global $MULTIFORMURL,$MULTIFORMDIR,$SPECIAL_VALUES,$aSessionVars;
8542
8543 if (empty($MULTIFORMDIR) && empty($MULTIFORMURL))
8544 {
8545 SendAlert(GetMessage(MSG_MULTIFORM));
8546 return (false);
8547 }
8548 $i_index = $aSessionVars["FormIndex"];
8549 $a_values["this_form_url"] = $aSessionVars["FormList"][$i_index]["URL"];
8550 //$a_values["prev_form"] = GetReturnLink($SPECIAL_VALUES["this_form"]);
8551 return (DoProcessTemplate($MULTIFORMDIR,$MULTIFORMURL,$s_template,$a_lines,
8552 $a_values,"",'SubstituteValueForPage'));
8553}
8554
8555 //
8556 // Output the multi-form template after filling in the fields.
8557 //
8558function OutputMultiFormTemplate($s_template,$a_values)
8559{
8560 $a_lines = array();
8561 if (!ProcessMultiFormTemplate($s_template,$a_values,$a_lines))
8562 Error("multi_form_failed",GetMessage(MSG_MULTIFORM_FAILED,
8563 array("NAME"=>$s_template)),false,false);
8564 else
8565 {
8566 $n_lines = count($a_lines);
8567 $s_buf = "";
8568 for ($ii = 0 ; $ii < $n_lines ; $ii++)
8569 {
8570 $s_buf .= $a_lines[$ii]."\n";
8571 unset($a_lines[$ii]); // free memory (hopefully)
8572 }
8573 unset($a_lines); // free memory (hopefully)
8574
8575 global $aSessionVars;
8576
8577 if (isset($aSessionVars["FormKeep"]))
8578 //
8579 // put in any values that are being forward-remembered
8580 //
8581 echo SetPreviousValues($s_buf,$aSessionVars["FormKeep"]);
8582 else
8583 echo $s_buf;
8584 }
8585}
8586
8587 //
8588 // Insert a preamble into a MIME message.
8589 //
8590function MimePreamble(&$a_lines,$a_mesg = array())
8591{
8592 $a_preamble = explode("\n",GetMessage(MSG_MIME_PREAMBLE));
8593 foreach ($a_preamble as $s_line)
8594 $a_lines[] = $s_line.HEAD_CRLF;
8595
8596 $a_lines[] = HEAD_CRLF; // blank line
8597 $b_need_blank = false;
8598 foreach ($a_mesg as $s_line)
8599 {
8600 $a_lines[] = $s_line.HEAD_CRLF;
8601 if (!empty($s_line))
8602 $b_need_blank = true;
8603 }
8604 if ($b_need_blank)
8605 $a_lines[] = HEAD_CRLF; // blank line
8606}
8607
8608 //
8609 // Create the HTML mail
8610 //
8611function HTMLMail(&$a_lines,&$a_headers,$s_body,$s_template,$s_missing,$s_filter,
8612 $s_boundary,$a_raw_fields,$b_no_plain)
8613{
8614 $s_charset = GetMailOption("CharSet");
8615 if (!isset($s_charset))
8616 $s_charset = "ISO-8859-1";
8617 if ($b_no_plain)
8618 {
8619 $b_multi = false;
8620 //
8621 // don't provide a plain text version - just the HTML
8622 //
8623 $a_headers['Content-Type'] = "text/html; charset=$s_charset";
8624 }
8625 else
8626 {
8627 $b_multi = true;
8628 $a_headers['Content-Type'] = "multipart/alternative; boundary=\"$s_boundary\"";
8629
8630 $a_pre_lines = explode("\n",GetMessage(MSG_MIME_HTML,
8631 array("NAME"=>$s_template)));
8632
8633 MimePreamble($a_lines,$a_pre_lines);
8634
8635 //
8636 // first part - the text version only
8637 //
8638 $a_lines[] = "--$s_boundary".HEAD_CRLF;
8639 $a_lines[] = "Content-Type: text/plain; charset=$s_charset".HEAD_CRLF;
8640 $a_lines[] = HEAD_CRLF; // blank line
8641 //
8642 // treat the body like one line, even though it isn't
8643 //
8644 $a_lines[] = $s_body;
8645 $a_lines[] = HEAD_CRLF; // blank line
8646 //
8647 // second part - the HTML version
8648 //
8649 $a_lines[] = "--$s_boundary".HEAD_CRLF;
8650 $a_lines[] = "Content-Type: text/html; charset=$s_charset".HEAD_CRLF;
8651 $a_lines[] = HEAD_CRLF; // blank line
8652 }
8653
8654 $a_html_lines = array();
8655 if (!ProcessTemplate($s_template,$a_html_lines,$a_raw_fields,$s_missing))
8656 return (false);
8657
8658 if (!empty($s_filter))
8659 //
8660 // treat the data like one line, even though it isn't
8661 //
8662 $a_lines[] = Filter($s_filter,$a_html_lines);
8663 else
8664 foreach ($a_html_lines as $s_line)
8665 $a_lines[] = $s_line;
8666
8667 if ($b_multi)
8668 {
8669 //
8670 // end
8671 //
8672 $a_lines[] = "--$s_boundary--".HEAD_CRLF;
8673 $a_lines[] = HEAD_CRLF; // blank line
8674 }
8675 return (true);
8676}
8677
8678 //
8679 // Add the contents of a file in base64 encoding.
8680 //
8681function AddFile(&$a_lines,$s_file_name,$i_file_size)
8682{
8683 global $php_errormsg;
8684
8685@ $fp = fopen($s_file_name,"rb");
8686 if ($fp === false)
8687 {
8688 SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_file_name,
8689 "TYPE"=>"attachment",
8690 "ERROR"=>CheckString($php_errormsg))));
8691 return (false);
8692 }
8693 //
8694 // PHP under IIS has problems with the filesize function when
8695 // the file is on another drive. So, we replaced a call
8696 // to filesize with the $i_file_size parameter (this occurred
8697 // in version 3.01).
8698 //
8699 $s_contents = fread($fp,$i_file_size);
8700 //
8701 // treat as a single line, even though it isn't
8702 //
8703 $a_lines[] = chunk_split(base64_encode($s_contents));
8704 fclose($fp);
8705 return (true);
8706}
8707
8708 //
8709 // Add the contents of a string in base64 encoding.
8710 //
8711function AddData(&$a_lines,$s_data)
8712{
8713 //
8714 // treat as a single line, even though it isn't
8715 //
8716 $a_lines[] = chunk_split(base64_encode($s_data));
8717 return (true);
8718}
8719
8720 //
8721 // Save an uploaded file to the given directory.
8722 //
8723function SaveFile($a_file_spec,$s_dir)
8724{
8725 global $php_errormsg;
8726
8727 //
8728 // if a replacement name has been specified, use that, otherwise
8729 // use the original name
8730 //
8731 if (isset($a_file_spec['new_name']))
8732 $s_file_name = basename($a_file_spec['new_name']);
8733 else
8734 $s_file_name = basename($a_file_spec['name']);
8735 $s_dest = $s_dir."/".$s_file_name;
8736 if (!move_uploaded_file($a_file_spec['tmp_name'],$s_dest))
8737 {
8738 SendAlert(GetMessage(MSG_SAVE_FILE,array(
8739 "FILE"=>$a_file_spec['tmp_name'],
8740 "DEST"=>$s_dest,
8741 "ERR"=>$php_errormsg)));
8742 return (false);
8743 }
8744 if (FILE_MODE != 0 && !chmod($s_dest,FILE_MODE))
8745 SendAlert(GetMessage(MSG_CHMOD,array(
8746 "FILE"=>$s_dest,
8747 "MODE"=>FILE_MODE,
8748 "ERR"=>$php_errormsg)));
8749 return (true);
8750}
8751
8752 //
8753 // Attach a file to the body of a MIME formatted email. $a_lines is the
8754 // current body, and is modified to include the file.
8755 // $a_file_spec must have the following values (just like an uploaded
8756 // file specification):
8757 // name the name of the file
8758 // type the mime type
8759 // tmp_name the name of the temporary file
8760 // size the size of the temporary file
8761 //
8762 // Alternatively, you supply the following instead of tmp_name and size:
8763 // data the data to attach
8764 //
8765function AttachFile(&$a_lines,$s_att_boundary,$a_file_spec,$s_charset)
8766{
8767 $a_lines[] = "--$s_att_boundary".HEAD_CRLF;
8768 //
8769 // if a replacement name has been specified, use that, otherwise
8770 // use the original name
8771 //
8772 if (isset($a_file_spec['new_name']))
8773 $s_file_name = $a_file_spec['new_name'];
8774 else
8775 $s_file_name = $a_file_spec['name'];
8776 $s_file_name = str_replace('"','',$s_file_name);
8777 $s_mime_type = $a_file_spec['type'];
8778 //
8779 // The following says that the data is encoded in
8780 // base64 and is an attachment. Once decoded the
8781 // character set of the decoded data is $s_charset.
8782 // (See RFC 1521 Section 5.)
8783 //
8784 $a_lines[] = "Content-Type: $s_mime_type; name=\"$s_file_name\"; charset=$s_charset".HEAD_CRLF;
8785 $a_lines[] = "Content-Transfer-Encoding: base64".HEAD_CRLF;
8786 $a_lines[] = "Content-Disposition: attachment; filename=\"$s_file_name\"".HEAD_CRLF;
8787 $a_lines[] = HEAD_CRLF; // blank line
8788 if (isset($a_file_spec['tmp_name']) && isset($a_file_spec['size']))
8789 return (AddFile($a_lines,$a_file_spec['tmp_name'],$a_file_spec['size']));
8790 if (!isset($a_file_spec['data']))
8791 {
8792 SendAlert(GetMessage(MSG_ATTACH_DATA));
8793 return (false);
8794 }
8795 return (AddData($a_lines,$a_file_spec['data']));
8796}
8797
8798 //
8799 // Reformat the email to be in MIME format.
8800 // Process file attachments and and fill out any
8801 // specified HTML template.
8802 //
8803function MakeMimeMail(&$s_body,&$a_headers,$a_raw_fields,$s_template = "",
8804 $s_missing = NULL,$b_no_plain = false,
8805 $s_filter = "",$a_file_vars = array(),
8806 $a_attach_spec = array())
8807{
8808 global $FM_VERS,$aPHPVERSION;
8809 global $SPECIAL_VALUES,$FILTER_ATTRIBS,$FILE_REPOSITORY;
8810
8811 $s_charset = GetMailOption("CharSet");
8812 if (!isset($s_charset))
8813 $s_charset = "ISO-8859-1";
8814 $b_att = $b_html = false;
8815 $b_got_filter = (isset($s_filter) && !empty($s_filter));
8816 if (isset($s_template) && !empty($s_template))
8817 {
8818 //
8819 // need PHP 4.0.5 for the preg_replace_callback function
8820 //
8821 if (!IsPHPAtLeast("4.0.5"))
8822 {
8823 SendAlert(GetMessage(MSG_PHP_HTML_TEMPLATES,
8824 array("PHPVERS"=>implode(".",$aPHPVERSION))));
8825 return (false);
8826 }
8827 $b_html = true;
8828 }
8829 if (count($a_file_vars) > 0)
8830 {
8831 if (!IsPHPAtLeast("4.0.3"))
8832 {
8833 SendAlert(GetMessage(MSG_PHP_FILE_UPLOADS,
8834 array("PHPVERS"=>implode(".",$aPHPVERSION))));
8835 return (false);
8836 }
8837 if (!FILEUPLOADS)
8838 SendAlert(GetMessage(MSG_FILE_UPLOAD));
8839 elseif ($FILE_REPOSITORY === "") // if storing on the server, don't attach
8840 foreach ($a_file_vars as $a_upload)
8841 {
8842 //
8843 // One customer reported:
8844 // Possible file upload attack detected: name='' temp name='none'
8845 // on PHP 4.1.2 on RAQ4.
8846 // So, we now also test for 'name'.
8847 //
8848 if (isset($a_upload['tmp_name']) && !empty($a_upload['tmp_name']) &&
8849 isset($a_upload['name']) && !empty($a_upload['name']))
8850 {
8851 $b_att = true;
8852 break;
8853 }
8854 }
8855 }
8856 //
8857 // check for an internally-generated attachment
8858 //
8859 if (isset($a_attach_spec["Data"]))
8860 $b_att = true;
8861
8862 $s_uniq = md5($s_body);
8863 $s_body_boundary = "BODY$s_uniq";
8864 $s_att_boundary = "PART$s_uniq";
8865 $a_headers['MIME-Version'] = "1.0 (produced by FormMail $FM_VERS from www.tectite.com)";
8866
8867 //
8868 // if the filter strips formatting, then we'll only have plain text
8869 // to send, even after the template has been used
8870 //
8871 if ($b_got_filter && IsFilterAttribSet($s_filter,"Strips"))
8872 //
8873 // no HTML if the filter strips the formatting
8874 //
8875 $b_html = false;
8876 $a_new = array();
8877 if ($b_att)
8878 {
8879 $a_headers['Content-Type'] = "multipart/mixed; boundary=\"$s_att_boundary\"";
8880
8881 MimePreamble($a_new);
8882 //
8883 // add the body of the email
8884 //
8885 $a_new[] = "--$s_att_boundary".HEAD_CRLF;
8886 if ($b_html)
8887 {
8888 $a_lines = $a_local_headers = array();
8889 if (!HTMLMail($a_lines,$a_local_headers,$s_body,$s_template,
8890 $s_missing,($b_got_filter) ? $s_filter : "",
8891 $s_body_boundary,$a_raw_fields,$b_no_plain))
8892 return (false);
8893 $a_new = array_merge($a_new,ExpandMailHeadersArray($a_local_headers));
8894 $a_new[] = HEAD_CRLF; // blank line after header
8895 $a_new = array_merge($a_new,$a_lines);
8896 }
8897 else
8898 {
8899 $a_new[] = "Content-Type: text/plain; charset=$s_charset".HEAD_CRLF;
8900 $a_new[] = HEAD_CRLF; // blank line
8901 //
8902 // treat the body like one line, even though it isn't
8903 //
8904 $a_new[] = $s_body;
8905 }
8906 //
8907 // now add the attachments or save to the $FILE_REPOSITORY
8908 //
8909 if (FILEUPLOADS && $FILE_REPOSITORY === "")
8910 foreach ($a_file_vars as $a_upload)
8911 {
8912 //
8913 // One customer reported:
8914 // Possible file upload attack detected: name='' temp name='none'
8915 // on PHP 4.1.2 on RAQ4.
8916 // So, we now also test for 'name'.
8917 //
8918 if (!isset($a_upload['tmp_name']) || empty($a_upload['tmp_name']) ||
8919 !isset($a_upload['name']) || empty($a_upload['name']))
8920 continue;
8921 if (!is_uploaded_file($a_upload['tmp_name']))
8922 {
8923 SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
8924 array("NAME"=>$a_upload['name'],
8925 "TEMP"=>$a_upload['tmp_name'])));
8926 continue;
8927 }
8928 if (MAX_FILE_UPLOAD_SIZE != 0 &&
8929 $a_upload['size'] > MAX_FILE_UPLOAD_SIZE*1024)
8930 UserError("upload_size",GetMessage(MSG_FILE_UPLOAD_SIZE,
8931 array("NAME"=>$a_upload['name'],
8932 "SIZE"=>$a_upload['size'],
8933 "MAX"=>MAX_FILE_UPLOAD_SIZE)));
8934 if (!AttachFile($a_new,$s_att_boundary,$a_upload,$s_charset))
8935 return (false);
8936 }
8937 if (isset($a_attach_spec["Data"]))
8938 {
8939 //
8940 // build a specification similar to a file upload
8941 //
8942 $a_file_spec["name"] = isset($a_attach_spec["Name"]) ?
8943 $a_attach_spec["Name"] :
8944 "attachment.dat";
8945 $a_file_spec["type"] = isset($a_attach_spec["MIME"]) ?
8946 $a_attach_spec["MIME"] :
8947 "text/plain";
8948 $a_file_spec["data"] = $a_attach_spec["Data"];
8949 if (!AttachFile($a_new,$s_att_boundary,$a_file_spec,
8950 isset($a_attach_spec["CharSet"]) ?
8951 $a_attach_spec["CharSet"] :
8952 $s_charset))
8953 return (false);
8954 }
8955 $a_new[] = "--$s_att_boundary--".HEAD_CRLF; // the end
8956 $a_new[] = HEAD_CRLF; // blank line
8957 }
8958 elseif ($b_html)
8959 {
8960 if (!HTMLMail($a_new,$a_headers,$s_body,$s_template,
8961 $s_missing,($b_got_filter) ? $s_filter : "",
8962 $s_body_boundary,$a_raw_fields,$b_no_plain))
8963 return (false);
8964 }
8965 else
8966 {
8967 $a_headers['Content-Type'] = "text/plain; charset=$s_charset";
8968 //
8969 // treat the body like one line, even though it isn't
8970 //
8971 $a_new[] = $s_body;
8972 }
8973
8974 $s_body = JoinLines(BODY_LF,$a_new);
8975 return (true);
8976}
8977
8978 //
8979 // to make a From line for the email
8980 //
8981function MakeFromLine($s_email,$s_name)
8982{
8983 $s_line = "";
8984 if (!empty($s_email))
8985 $s_line .= $s_email." ";
8986 if (!empty($s_name))
8987 $s_line .= "(".$s_name.")";
8988 return ($s_line);
8989}
8990
8991 //
8992 // Return two sets of plain text output: the filtered fields and the
8993 // non-filtered fields.
8994 //
8995function GetFilteredOutput($a_fld_order,$a_clean_fields,$s_filter,$a_filter_list)
8996{
8997 //
8998 // find the non-filtered fields and make unfiltered text from them
8999 //
9000 $a_unfiltered_list = array();
9001 $n_flds = count($a_fld_order);
9002 for ($ii = 0 ; $ii < $n_flds ; $ii++)
9003 if (!in_array($a_fld_order[$ii],$a_filter_list))
9004 $a_unfiltered_list[] = $a_fld_order[$ii];
9005 $s_unfiltered_results = MakeFieldOutput($a_unfiltered_list,$a_clean_fields);
9006 //
9007 // filter the specified fields only
9008 //
9009 $s_filtered_results = MakeFieldOutput($a_filter_list,$a_clean_fields);
9010 $s_filtered_results = Filter($s_filter,$s_filtered_results);
9011 return (array($s_unfiltered_results,$s_filtered_results));
9012}
9013
9014 //
9015 // Make a plain text email body
9016 //
9017function MakePlainEmail($a_fld_order,$a_clean_fields,
9018 $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,$a_filter_list)
9019{
9020 global $SPECIAL_VALUES,$aPHPVERSION;
9021
9022 $s_unfiltered_results = $s_filtered_results = "";
9023 $b_got_filter = (isset($s_filter) && !empty($s_filter));
9024 if ($b_got_filter)
9025 if (isset($a_filter_list) && count($a_filter_list) > 0)
9026 $b_limited_filter = true;
9027 else
9028 $b_limited_filter = false;
9029 $b_used_template = false;
9030 if (IsMailOptionSet("PlainTemplate"))
9031 {
9032 //
9033 // need PHP 4.0.5 for the preg_replace_callback function
9034 //
9035 if (!IsPHPAtLeast("4.0.5"))
9036 SendAlert(GetMessage(MSG_PHP_PLAIN_TEMPLATES,
9037 array("PHPVERS"=>implode(".",$aPHPVERSION))));
9038 else
9039 {
9040 $s_template = GetMailOption("PlainTemplate");
9041 if (ProcessTemplate($s_template,$a_lines,$a_raw_fields,
9042 GetMailOption('TemplateMissing'),
9043 'SubstituteValuePlain'))
9044 {
9045 $b_used_template = true;
9046 $s_unfiltered_results = implode(BODY_LF,$a_lines);
9047 if ($b_got_filter)
9048 {
9049 //
9050 // with a limited filter, the template goes unfiltered
9051 // and the named fields get filtered
9052 //
9053 if ($b_limited_filter)
9054 list($s_discard,$s_filtered_results) =
9055 GetFilteredOutput($a_fld_order,$a_clean_fields,
9056 $s_filter,$a_filter_list);
9057 else
9058 {
9059 $s_filtered_results = Filter($s_filter,$s_unfiltered_results);
9060 $s_unfiltered_results = "";
9061 }
9062 }
9063 }
9064 }
9065 }
9066 if (!$b_used_template)
9067 {
9068 $res_hdr = "";
9069
9070 if (IsMailOptionSet("DupHeader"))
9071 {
9072 //
9073 // write some standard mail headers
9074 //
9075 $res_hdr = "To: $s_to".BODY_LF;
9076 if (!empty($s_cc))
9077 $res_hdr .= "Cc: $s_cc".BODY_LF;
9078 if (!empty($SPECIAL_VALUES["email"]))
9079 $res_hdr .= MakeFromLine($SPECIAL_VALUES["email"],
9080 $SPECIAL_VALUES["realname"]);
9081 $res_hdr .= BODY_LF;
9082 if (IsMailOptionSet("StartLine"))
9083 $res_hdr .= "--START--".BODY_LF; // signals the beginning of the text to filter
9084 }
9085
9086 //
9087 // put the realname and the email address at the top of the results
9088 // (if not excluded)
9089 //
9090 if (!IsMailExcluded("realname"))
9091 {
9092 array_unshift($a_fld_order,"realname");
9093 $a_clean_fields["realname"] = $SPECIAL_VALUES["realname"];
9094 }
9095 if (!IsMailExcluded("email"))
9096 {
9097 array_unshift($a_fld_order,"email");
9098 $a_clean_fields["email"] = $SPECIAL_VALUES["email"];
9099 }
9100 if ($b_got_filter)
9101 {
9102 if ($b_limited_filter)
9103 list($s_unfiltered_results,$s_filtered_results) =
9104 GetFilteredOutput($a_fld_order,$a_clean_fields,
9105 $s_filter,$a_filter_list);
9106 else
9107 {
9108 //
9109 // make text output and filter it (filter all fields)
9110 //
9111 $s_filtered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
9112 $s_filtered_results = Filter($s_filter,$s_filtered_results);
9113 }
9114 }
9115 else
9116 {
9117//SendAlert("There are ".count($a_fld_order)." fields in the order array");
9118//SendAlert("Here is the clean fields array:\r\n".var_export($a_clean_fields,true));
9119 $s_unfiltered_results = MakeFieldOutput($a_fld_order,$a_clean_fields);
9120 }
9121 $s_unfiltered_results = $res_hdr.$s_unfiltered_results;
9122 }
9123 $s_results = $s_unfiltered_results;
9124 if ($b_got_filter && !empty($s_filtered_results))
9125 {
9126 if (!empty($s_results))
9127 $s_results .= BODY_LF;
9128 $s_results .= $s_filtered_results;
9129 }
9130 return (array($s_results,$s_unfiltered_results,$s_filtered_results));
9131}
9132
9133 //
9134 // send the given results to the given email addresses
9135 //
9136function SendResults($a_fld_order,$a_clean_fields,$s_to,$s_cc,$s_bcc,$a_raw_fields)
9137{
9138 global $SPECIAL_VALUES,$aFileVars,$FILE_REPOSITORY;
9139
9140 //
9141 // check for a filter and how to use it
9142 //
9143 $b_got_filter = (isset($SPECIAL_VALUES["filter"]) && !empty($SPECIAL_VALUES["filter"]));
9144 $b_filter_attach = false;
9145 $a_attach_spec = array();
9146 $s_filter = "";
9147 $a_filter_list = array();
9148 if ($b_got_filter)
9149 {
9150 $s_filter = $SPECIAL_VALUES["filter"];
9151 if (isset($SPECIAL_VALUES["filter_fields"]) && !empty($SPECIAL_VALUES["filter_fields"]))
9152 {
9153 $b_limited_filter = true;
9154 $a_filter_list = TrimArray(explode(",",$SPECIAL_VALUES["filter_fields"]));
9155 }
9156 else
9157 $b_limited_filter = false;
9158 $s_filter_attach_name = GetFilterOption("Attach");
9159 if (isset($s_filter_attach_name))
9160 if (!is_string($s_filter_attach_name) || empty($s_filter_attach_name))
9161 SendAlert(GetMessage(MSG_ATTACH_NAME));
9162 else
9163 {
9164 $b_filter_attach = true;
9165 $a_attach_spec = array("Name"=>$s_filter_attach_name);
9166 if (($s_mime = GetFilterAttrib($s_filter,"MIME")) !== false)
9167 $a_attach_spec["MIME"] = $s_mime;
9168 //
9169 // Regarding the character set...
9170 // A filter will not generally change the character set
9171 // of the message, however, if it does, then we
9172 // provide that information to the MIME encoder.
9173 // Remember: this character set specification refers
9174 // to the data *after* the effect of the filter
9175 // has been reversed (e.g. an encrypted message
9176 // in UTF-8 is in UTF-8 when it is decrypted).
9177 //
9178 if (($s_cset = GetFilterAttrib($s_filter,"CharSet")) !== false)
9179 $a_attach_spec["CharSet"] = $s_cset;
9180 }
9181 }
9182
9183 //
9184 // check the need for MIME formatted mail
9185 //
9186 $b_mime_mail = (IsMailOptionSet("HTMLTemplate") || count($aFileVars) > 0 ||
9187 $b_filter_attach);
9188
9189 //
9190 // create the email header lines - CC, BCC, and From
9191 //
9192 $a_headers = array();
9193 if (!empty($s_cc))
9194 $a_headers['Cc'] = $s_cc;
9195 //
9196 // note that BCC is documented to not work prior to PHP 4.3
9197 //
9198 if (!empty($s_bcc))
9199 {
9200 global $aPHPVERSION;
9201
9202 if ($aPHPVERSION[0] < 4 || ($aPHPVERSION[0] == 4 && $aPHPVERSION[1] < 3))
9203 SendAlert(GetMessage(MSG_PHP_BCC,
9204 array("PHPVERS"=>implode(".",$aPHPVERSION))));
9205 $a_headers['Bcc'] = $s_bcc;
9206 }
9207 //
9208 // create the From address
9209 //
9210 // Some servers won't let you set the email address to the
9211 // submitter of the form. Therefore, use FromAddr if it's been
9212 // specified. If it's empty, don't specify a sender.
9213 //
9214 $s_sender = GetMailOption("FromAddr");
9215 if (!isset($s_sender))
9216 {
9217 $s_sender = "";
9218 if (!empty($SPECIAL_VALUES["email"]))
9219 $a_headers['From'] = MakeFromLine($SPECIAL_VALUES["email"],
9220 $SPECIAL_VALUES["realname"]);
9221 }
9222 elseif ($s_sender !== "")
9223 $s_sender = $a_headers['From'] = UnMangle($s_sender);
9224
9225 if ($s_sender === "")
9226 if (SET_SENDER_FROM_EMAIL)
9227 $s_sender = $SPECIAL_VALUES["email"];
9228
9229 //
9230 // special case: if there is only one non-special string value, then
9231 // format it as an email (unless an option says not to)
9232 //
9233 $a_keys = array_keys($a_raw_fields);
9234 if (count($a_keys) == 1 && is_string($a_raw_fields[$a_keys[0]]) &&
9235 !IsMailOptionSet("AlwaysList") && !IsMailOptionSet("DupHeader"))
9236 {
9237 if (IsMailExcluded($a_keys[0]))
9238 SendAlert("Exclusion of single field '".$a_keys[0]."' ignored");
9239 $s_value = $a_raw_fields[$a_keys[0]];
9240 //
9241 // replace carriage return/linefeeds with <br>
9242 //
9243 $s_value = str_replace("\r\n",'<br />',$s_value);
9244 //
9245 // replace lone linefeeds with <br>
9246 //
9247 $s_value = str_replace("\n",'<br />',$s_value);
9248 //
9249 // remove lone carriage returns
9250 //
9251 $s_value = str_replace("\r","",$s_value);
9252 //
9253 // replace all control chars with <br>
9254 //
9255 $s_value = preg_replace('/[[:cntrl:]]+/','<br />',$s_value);
9256 //
9257 // strip HTML (note that all the <br> above will now be
9258 // replaced with BODY_LF)
9259 //
9260 $s_value = StripHTML($s_value,BODY_LF);
9261
9262 if ($b_mime_mail)
9263 {
9264 if ($b_got_filter)
9265 {
9266 //
9267 // filter the whole value (ignore filter_fields for this
9268 // special case) if a filter has been specified
9269 //
9270 $s_results = Filter($s_filter,$s_value);
9271 if ($b_filter_attach)
9272 {
9273 $a_attach_spec["Data"] = $s_results;
9274 //
9275 // KeepInLine keeps the filtered version inline as well
9276 // as an attachment
9277 //
9278 if (!IsFilterOptionSet("KeepInLine"))
9279 $s_results = "";
9280 $s_filter = ""; // no more filtering
9281 }
9282 }
9283 else
9284 $s_results = $s_value;
9285
9286 //
9287 // send this single value off to get formatted in a MIME
9288 // email
9289 //
9290 if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
9291 GetMailOption('HTMLTemplate'),
9292 GetMailOption('TemplateMissing'),
9293 IsMailOptionSet("NoPlain"),
9294 $s_filter,$aFileVars,$a_attach_spec))
9295 return (false);
9296 }
9297 elseif ($b_got_filter)
9298 //
9299 // filter the whole value (ignore filter_fields for this special case)
9300 // if a filter has been specified
9301 //
9302 $s_results = Filter($s_filter,$s_value);
9303 else
9304 $s_results = $s_value;
9305 }
9306 else
9307 {
9308 if ($b_mime_mail)
9309 {
9310 //
9311 // get the plain text version of the email then send it
9312 // to get MIME formatted
9313 //
9314 list($s_results,$s_unfiltered_results,$s_filtered_results) =
9315 MakePlainEmail($a_fld_order,$a_clean_fields,
9316 $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
9317 $a_filter_list);
9318 if ($b_filter_attach)
9319 {
9320 //
9321 // attached the filtered results
9322 //
9323 $a_attach_spec["Data"] = $s_filtered_results;
9324 //
9325 // KeepInLine keeps the filtered version inline as well
9326 // as an attachment
9327 //
9328 if (!IsFilterOptionSet("KeepInLine"))
9329 //
9330 // put the unfiltered results in the body of the message
9331 //
9332 $s_results = $s_unfiltered_results;
9333 $s_filter = ""; // no more filtering
9334 }
9335 if (!MakeMimeMail($s_results,$a_headers,$a_raw_fields,
9336 GetMailOption('HTMLTemplate'),
9337 GetMailOption('TemplateMissing'),
9338 IsMailOptionSet("NoPlain"),
9339 $s_filter,$aFileVars,$a_attach_spec))
9340 return (false);
9341 }
9342 else
9343 {
9344 list($s_results,$s_unfiltered_results,$s_filtered_results) =
9345 MakePlainEmail($a_fld_order,$a_clean_fields,
9346 $s_to,$s_cc,$s_bcc,$a_raw_fields,$s_filter,
9347 $a_filter_list);
9348 if (!$b_got_filter && IsMailOptionSet("CharSet"))
9349 //
9350 // sending plain text email, and the CharSet has been
9351 // specified; include a header
9352 //
9353 $a_headers['Content-Type'] = "text/plain; charset=".GetMailOption("CharSet");
9354 }
9355 }
9356
9357 //
9358 // append the environment variables report
9359 //
9360 if (isset($SPECIAL_VALUES["env_report"]))
9361 {
9362 $s_results .= BODY_LF."==================================".BODY_LF;
9363 $s_results .= BODY_LF.GetEnvVars(TrimArray(explode(",",$SPECIAL_VALUES["env_report"])),BODY_LF);
9364 }
9365 //
9366 // now save uploaded files to the repository
9367 //
9368 if (FILEUPLOADS && $FILE_REPOSITORY !== "")
9369 {
9370 foreach ($aFileVars as $m_file_key=>$a_upload)
9371 {
9372 //
9373 // One customer reported:
9374 // Possible file upload attack detected: name='' temp name='none'
9375 // on PHP 4.1.2 on RAQ4.
9376 // So, we now also test for 'name'.
9377 //
9378 if (!isset($a_upload['tmp_name']) || empty($a_upload['tmp_name']) ||
9379 !isset($a_upload['name']) || empty($a_upload['name']))
9380 continue;
9381 if (!is_uploaded_file($a_upload['tmp_name']))
9382 {
9383 SendAlert(GetMessage(MSG_FILE_UPLOAD_ATTACK,
9384 array("NAME"=>$a_upload['name'],
9385 "TEMP"=>$a_upload['tmp_name'])));
9386 continue;
9387 }
9388 if (MAX_FILE_UPLOAD_SIZE != 0 &&
9389 $a_upload['size'] > MAX_FILE_UPLOAD_SIZE*1024)
9390 UserError("upload_size",GetMessage(MSG_FILE_UPLOAD_SIZE,
9391 array("NAME"=>$a_upload['name'],
9392 "SIZE"=>$a_upload['size'],
9393 "MAX"=>MAX_FILE_UPLOAD_SIZE)));
9394 if (!SaveFile($a_upload,$FILE_REPOSITORY))
9395 return (false);
9396 //
9397 // Now that the file has been saved, "is_uploaded_file"
9398 // will return false. So, we create a flag to say it was
9399 // valid.
9400 //
9401 $aFileVars[$m_file_key]['moved'] = true;
9402 }
9403 }
9404 //
9405 // send the mail - assumes the email addresses have already been checked
9406 //
9407 return (SendCheckedMail($s_to,$SPECIAL_VALUES["subject"],$s_results,
9408 $s_sender,$a_headers));
9409}
9410
9411 //
9412 // append an entry to a log file
9413 //
9414function WriteLog($log_file)
9415{
9416 global $SPECIAL_VALUES,$php_errormsg;
9417
9418@ $log_fp = fopen($log_file,"a");
9419 if ($log_fp === false)
9420 {
9421 SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$log_file,
9422 "TYPE"=>"log",
9423 "ERROR"=>CheckString($php_errormsg))));
9424 return;
9425 }
9426 $date = gmdate("H:i:s d-M-y T");
9427 $entry = $date.":".$SPECIAL_VALUES["email"].",".
9428 $SPECIAL_VALUES["realname"].",".$SPECIAL_VALUES["subject"]."\n";
9429 fwrite($log_fp,$entry);
9430 fclose($log_fp);
9431}
9432
9433 //
9434 // write the data to a comma-separated-values file
9435 //
9436function WriteCSVFile($s_csv_file,$a_vars)
9437{
9438 global $SPECIAL_VALUES,$CSVSEP,$CSVINTSEP,$CSVQUOTE,$CSVOPEN,$CSVLINE;
9439
9440 //
9441 // create an array of column values in the order specified
9442 // in $SPECIAL_VALUES["csvcolumns"]
9443 //
9444 $a_column_list = $SPECIAL_VALUES["csvcolumns"];
9445 if (!isset($a_column_list) || empty($a_column_list) || !is_string($a_column_list))
9446 {
9447 SendAlert(GetMessage(MSG_CSVCOLUMNS,array("VALUE"=>$a_column_list)));
9448 return;
9449 }
9450 if (!isset($s_csv_file) || empty($s_csv_file) || !is_string($s_csv_file))
9451 {
9452 SendAlert(GetMessage(MSG_CSVFILE,array("VALUE"=>$s_csv_file)));
9453 return;
9454 }
9455
9456@ $fp = fopen($s_csv_file,"a".$CSVOPEN);
9457 if ($fp === false)
9458 {
9459 SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$s_csv_file,
9460 "TYPE"=>"CSV",
9461 "ERROR"=>CheckString($php_errormsg))));
9462 return;
9463 }
9464
9465 //
9466 // convert the column list to an array, trim the names too
9467 //
9468 $a_column_list = TrimArray(explode(",",$a_column_list));
9469 $n_columns = count($a_column_list);
9470
9471 //
9472 // if the file is currently empty, put the column names in the first line
9473 //
9474 if (filesize($s_csv_file) == 0)
9475 {
9476 for ($ii = 0 ; $ii < $n_columns ; $ii++)
9477 {
9478 fwrite($fp,$CSVQUOTE.$a_column_list[$ii].$CSVQUOTE);
9479 if ($ii < $n_columns-1)
9480 fwrite($fp,"$CSVSEP");
9481 }
9482 fwrite($fp,$CSVLINE);
9483 }
9484
9485// $debug = "";
9486// $debug .= "gpc -> ".get_magic_quotes_gpc()."\n";
9487// $debug .= "runtime -> ".get_magic_quotes_runtime()."\n";
9488 for ($ii = 0 ; $ii < $n_columns ; $ii++)
9489 {
9490 $s_col_name = $a_column_list[$ii];
9491 //
9492 // columns can be missing from some form submission and present
9493 // from others
9494 //
9495 if (isset($a_vars[$s_col_name]))
9496 $m_value = $a_vars[$s_col_name];
9497 else
9498 $m_value = "";
9499
9500 if (LIMITED_IMPORT)
9501 //
9502 // the target database doesn't understand escapes, so
9503 // remove various things, including newlines and truncate
9504 //
9505 $m_value = CleanValue($m_value,false);
9506 else
9507 //
9508 // the target database does understand escapes, so
9509 // we have to slash any slashes
9510 //
9511 $m_value = str_replace("\\","\\\\",$m_value);
9512 //
9513 // convert quotes, depending on the setting of $CSVQUOTE
9514 //
9515 switch ($CSVQUOTE)
9516 {
9517 case '"':
9518 //
9519 // convert double quotes in the data to single quotes
9520 //
9521 $m_value = str_replace("\"","'",$m_value);
9522 break;
9523 case '\'':
9524 //
9525 // convert single quotes in the data to double quotes
9526 //
9527 $m_value = str_replace("'","\"",$m_value);
9528 break;
9529 default:
9530 //
9531 // otherwise, leave the data unchanged
9532 //
9533 break;
9534 }
9535 //
9536 // we handle arrays and strings
9537 //
9538 if (is_array($m_value))
9539 //
9540 // separate the values with the internal field separator
9541 //
9542 $m_value = implode("$CSVINTSEP",$m_value);
9543
9544// $debug .= $a_column_list[$ii]." => ".$m_value."\n";
9545 fwrite($fp,$CSVQUOTE.$m_value.$CSVQUOTE);
9546 if ($ii < $n_columns-1)
9547 fwrite($fp,"$CSVSEP");
9548 }
9549 fwrite($fp,$CSVLINE);
9550 fclose($fp);
9551// CreatePage($debug);
9552// exit;
9553}
9554
9555function CheckConfig()
9556{
9557 global $TARGET_EMAIL,$CONFIG_CHECK;
9558
9559 $a_mesgs = array();
9560 if (in_array("TARGET_EMAIL",$CONFIG_CHECK))
9561 {
9562 //
9563 // $TARGET_EMAIL values should begin with ^ and end with $
9564 //
9565 for ($ii = 0 ; $ii < count($TARGET_EMAIL) ; $ii++)
9566 {
9567 $s_pattern = $TARGET_EMAIL[$ii];
9568 if (substr($s_pattern,0,1) != '^')
9569 $a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_START,
9570 array("PAT"=>$s_pattern));
9571 if (substr($s_pattern,-1) != '$')
9572 $a_mesgs[] = GetMessage(MSG_TARG_EMAIL_PAT_END,
9573 array("PAT"=>$s_pattern));
9574 }
9575 }
9576 if (count($a_mesgs) > 0)
9577 SendAlert(GetMessage(MSG_CONFIG_WARN,
9578 array("MESGS"=>implode("\n",$a_mesgs))),false,true);
9579}
9580
9581 //
9582 // append an entry to the Auto Responder log file
9583 //
9584function WriteARLog($s_to,$s_subj,$s_info)
9585{
9586 global $LOGDIR,$AUTORESPONDLOG,$aServerVars,$php_errormsg;
9587
9588 if (!isset($LOGDIR) || !isset($AUTORESPONDLOG) ||
9589 empty($LOGDIR) || empty($AUTORESPONDLOG))
9590 return;
9591
9592 $log_file = $LOGDIR."/".$AUTORESPONDLOG;
9593@ $log_fp = fopen($log_file,"a");
9594 if ($log_fp === false)
9595 {
9596 SendAlert(GetMessage(MSG_FILE_OPEN_ERROR,array("NAME"=>$log_file,
9597 "TYPE"=>"log",
9598 "ERROR"=>CheckString($php_errormsg))));
9599 return;
9600 }
9601 $a_entry = array();
9602 $a_entry[] = gmdate("H:i:s d-M-y T"); // date/time in GMT
9603 $a_entry[] = $aServerVars['REMOTE_ADDR']; // remote IP address
9604 $a_entry[] = $s_to; // target email address
9605 $a_entry[] = $s_subj; // subject line
9606 $a_entry[] = $s_info; // information
9607
9608 $s_log_entry = implode(",",$a_entry)."\n";
9609 fwrite($log_fp,$s_log_entry);
9610 fclose($log_fp);
9611}
9612
9613 //
9614 // Send an email response to the user.
9615 //
9616function AutoRespond($s_to,$s_subj,$a_values)
9617{
9618 global $aPHPVERSION,$SPECIAL_VALUES,$FROM_USER;
9619
9620 //
9621 // need PHP 4.0.5 for the preg_replace_callback function
9622 //
9623 if (!IsPHPAtLeast("4.0.5"))
9624 {
9625 SendAlert(GetMessage(MSG_PHP_AUTORESP,
9626 array("PHPVERS"=>implode(".",$aPHPVERSION))));
9627 return (false);
9628 }
9629
9630 $a_headers = array();
9631 $s_mail_text = "";
9632 $s_from_addr = "";
9633
9634 if (isset($FROM_USER) && !empty($FROM_USER))
9635 {
9636 if ($FROM_USER != "NONE")
9637 $s_from_addr = $a_headers['From'] = $FROM_USER;
9638 }
9639 else
9640 {
9641 global $SERVER;
9642
9643 $s_from_addr = "FormMail@".$SERVER;
9644 $a_headers['From'] = $s_from_addr;
9645 }
9646
9647 if (IsAROptionSet('PlainTemplate'))
9648 {
9649 $s_template = GetAROption("PlainTemplate");
9650 if (!ProcessTemplate($s_template,$a_lines,$a_values,
9651 GetAROption('TemplateMissing'),
9652 'SubstituteValuePlain'))
9653 return (false);
9654 $s_mail_text = implode(BODY_LF,$a_lines);
9655 }
9656 if (IsAROptionSet("HTMLTemplate"))
9657 {
9658 if (!MakeMimeMail($s_mail_text,$a_headers,$a_values,
9659 GetAROption("HTMLTemplate"),
9660 GetAROption('TemplateMissing')))
9661 return (false);
9662 }
9663 return (SendCheckedMail($s_to,$s_subj,$s_mail_text,$s_from_addr,$a_headers));
9664}
9665
9666/*
9667 * The main logic starts here....
9668 */
9669
9670 //
9671 // First, a special case; if formmail.php is called like this:
9672 // http://.../formmail.php?testalert=1
9673 // it sends a test message to the default alert address with some
9674 // information about your PHP version and the DOCUMENT_ROOT.
9675 //
9676if (isset($aGetVars["testalert"]) && $aGetVars["testalert"] == 1)
9677{
9678 function ShowServerVar($s_name)
9679 {
9680 global $aServerVars;
9681
9682 return (isset($aServerVars[$s_name]) ? $aServerVars[$s_name] : "-not set-");
9683 }
9684 $sAlert = GetMessage(MSG_ALERT,
9685 array("LANG"=>$sLangID,
9686 "PHPVERS"=>implode(".",$aPHPVERSION),
9687 "FM_VERS"=>$FM_VERS,
9688 "SERVER"=>(IsServerWindows() ? "Windows" : "non-Windows"),
9689 "DOCUMENT_ROOT"=>ShowServerVar('DOCUMENT_ROOT'),
9690 "SCRIPT_FILENAME"=>ShowServerVar('SCRIPT_FILENAME'),
9691 "PATH_TRANSLATED"=>ShowServerVar('PATH_TRANSLATED'),
9692 "REAL_DOCUMENT_ROOT"=>CheckString($REAL_DOCUMENT_ROOT),
9693 ));
9694
9695 if (DEF_ALERT == "")
9696 echo "<p>".GetMessage(MSG_NO_DEF_ALERT)."</p>";
9697 elseif (SendAlert($sAlert,false,true))
9698 echo "<p>".GetMessage(MSG_TEST_SENT)."</p>";
9699 else
9700 echo "<p>".GetMessage(MSG_TEST_FAILED)."</p>";
9701 exit;
9702}
9703
9704if (isset($aGetVars["testlang"]) && $aGetVars["testlang"] == 1)
9705{
9706 if (!IsPHPAtLeast("4.1.0"))
9707 {
9708 ?>
9709 <p>testlang feature only works with PHP version 4.1.0 or later</p>
9710 <?php
9711 }
9712 else
9713 {
9714 function ShowMessages()
9715 {
9716 global $aMessages,$sLangID,$bShowMesgNumbers,$aGetVars;
9717
9718 //
9719 // force message numbers on unless "mnums=no"
9720 //
9721 if (isset($aGetVars["mnums"]) && $aGetVars["mnums"] == "no")
9722 $bShowMesgNumbers = false;
9723 else
9724 $bShowMesgNumbers = true;
9725
9726 LoadBuiltinLanguage();
9727
9728 $s_def_lang = $sLangID;
9729 $a_def_mesgs = $aMessages;
9730
9731 LoadLanguageFile();
9732
9733 $s_active_lang = $sLangID;
9734 $a_active_mesgs = $aMessages;
9735
9736 $a_list = get_defined_constants();
9737 echo "<table border=\"1\" cellpadding=\"10\" width=\"95%\">\n";
9738 echo "<tr>\n";
9739 echo "<th>\n";
9740 echo "Message Number";
9741 echo "</th>\n";
9742 echo "<th>\n";
9743 echo "$s_def_lang";
9744 echo "</th>\n";
9745 echo "<th>\n";
9746 echo "$s_active_lang";
9747 echo "</th>\n";
9748 echo "</tr>\n";
9749 foreach ($a_list as $s_name=>$i_value)
9750 {
9751 if (substr($s_name,0,4) == "MSG_")
9752 {
9753 echo "<tr>\n";
9754 echo "<td valign=\"top\">\n";
9755 echo "$s_name ($i_value)";
9756 echo "</td>\n";
9757 echo "<td valign=\"top\">\n";
9758 $aMessages = $a_def_mesgs;
9759 $s_def_msg = GetMessage((int) $i_value,array(),true,true);
9760 echo nl2br(htmlentities($s_def_msg));
9761 echo "</td>\n";
9762 echo "<td valign=\"top\">\n";
9763 $aMessages = $a_active_mesgs;
9764 $s_act_msg = GetMessage((int) $i_value,array(),true,true);
9765 if ($s_def_msg == $s_act_msg)
9766 echo "<i>identical</i>\n";
9767 else
9768 echo nl2br(htmlentities($s_act_msg));
9769 echo "</td>\n";
9770 echo "</tr>\n";
9771 }
9772 }
9773 echo "</table>\n";
9774 }
9775 ShowMessages();
9776 }
9777 exit;
9778}
9779
9780 //
9781 // Scan the Multi form sequence values and build up the values that
9782 // were submitted to the given form index.
9783 //
9784function GetMultiValues($a_form_list,$i_form_index,$a_order = array(),
9785 $a_clean = array(),
9786 $a_raw_data = array(),
9787 $a_all_data = array())
9788{
9789 $a_ret_clean = $a_ret_raw = $a_ret_all = array();
9790 for ($ii = 0 ; $ii < $i_form_index ; $ii++)
9791 {
9792 //
9793 // only add a field to the order if it's not already there
9794 //
9795 $a_form_order = $a_form_list[$ii]["ORDER"];
9796 $n_order = count($a_form_order);
9797 for ($jj = 0 ; $jj < $n_order ; $jj++)
9798 {
9799 if (array_search($a_form_order[$jj],$a_order) === false)
9800 $a_order[] = $a_form_order[$jj];
9801 }
9802 $a_ret_clean = array_merge($a_ret_clean,$a_form_list[$ii]["CLEAN"]);
9803 $a_ret_raw = array_merge($a_ret_raw,$a_form_list[$ii]["RAWDATA"]);
9804 $a_ret_all = array_merge($a_ret_all,$a_form_list[$ii]["ALLDATA"]);
9805 }
9806 //
9807 // later values must take precedence to earlier values,
9808 // so merge in the passed-in data last
9809 //
9810 $a_ret_clean = array_merge($a_ret_clean,$a_clean);
9811 $a_ret_raw = array_merge($a_ret_raw,$a_raw_data);
9812 $a_ret_all = array_merge($a_ret_all,$a_all_data);
9813 return (array($a_order,$a_ret_clean,$a_ret_raw,$a_ret_all));
9814}
9815
9816$bMultiForm = false;
9817
9818 //
9819 // Multi-page form sequencing is complicated....
9820 // Requirements:
9821 // 1. The first page in a multi-page form sequence must provide:
9822 // - multi_start field set to 1
9823 // - this_form field (it's own URL)
9824 // - next_form field (multi-page form template name)
9825 // 2. Subsequent pages must provide either:
9826 // next_form (the next template name in the sequence)
9827 // OR
9828 // good_url or good_template or neither; this terminates
9829 // the multi-page processing and provides the final URL.
9830 // Logic:
9831 // 1. We create session variables to contain information about
9832 // the sequence.
9833 // 2. On the first submission from the starting form, we record
9834 // its "this_form" URL and the data submitted.
9835 // We also create a URL (to FormMail) that will allow return
9836 // to the *next* form in the sequence.
9837 // 3. On submission from other forms in the sequence, we record
9838 // the data that was submitted so we can return to that
9839 // form with the user's data re-filled into the form.
9840 // We also create a URL (to FormMail) that will allow return
9841 // to the *next* form in the sequence.
9842 // 4. A return URL contains "return=index" where index is the
9843 // form sequence index number. This is a URL to FormMail.
9844 // FormMail gets the template name or URL (URL only for the
9845 // starting form) and outputs the requested HTML form. It also
9846 // truncates the session data for forms after the returned-to
9847 // one.
9848 //
9849
9850 //
9851 // Return to a previous form in a sequence.
9852 //
9853function MultiFormReturn($i_return_to)
9854{
9855 global $aSessionVars;
9856 global $iFormIndex;
9857
9858 if (!isset($aSessionVars["FormList"]) ||
9859 !isset($aSessionVars["FormIndex"]) ||
9860 $i_return_to < 0 ||
9861 $i_return_to > $aSessionVars["FormIndex"])
9862 Error("cannot_return",GetMessage(MSG_CANNOT_RETURN,
9863 array("TO"=>$i_return_to,
9864 "TOPINDEX"=>(
9865 isset($aSessionVars["FormIndex"]) ?
9866 $aSessionVars["FormIndex"] :
9867 "<undefined>"))),
9868 false,false);
9869 assert($i_return_to < count($aSessionVars["FormList"]));
9870 $a_form_def = $aSessionVars["FormList"][$i_return_to];
9871 $aSessionVars["FormList"] = array_slice($aSessionVars["FormList"],0,$i_return_to+1);
9872 $aSessionVars["FormIndex"] = $iFormIndex = $i_return_to;
9873 if (isset($a_form_def["FORM"]))
9874 {
9875 list(,,$a_values,) = GetMultiValues($aSessionVars["FormList"],$i_return_to);
9876 $a_lines = array();
9877 if (ProcessMultiFormTemplate($a_form_def["FORM"],$a_values,$a_lines))
9878 {
9879 $n_lines = count($a_lines);
9880 $s_buf = "";
9881 for ($ii = 0 ; $ii < $n_lines ; $ii++)
9882 {
9883 $s_buf .= $a_lines[$ii]."\n";
9884 unset($a_lines[$ii]); // free memory (hopefully)
9885 }
9886 unset($a_lines); // free memory (hopefully)
9887 //
9888 // put in the values that the user previously submitted
9889 // to this form
9890 //
9891 echo SetPreviousValues($s_buf,$a_form_def["RAWDATA"]);
9892 }
9893 else
9894 Error("multi_form_failed",GetMessage(MSG_MULTIFORM_FAILED,
9895 array("NAME"=>$s_template)),false,false);
9896 }
9897 else
9898 ProcessReturnToForm($a_form_def["URL"],$a_form_def["RAWDATA"]);
9899 //echo "Returned to $i_return_to";
9900}
9901
9902 //
9903 // Store any data just submitted and specified as "multi_keep".
9904 //
9905function MultiKeep()
9906{
9907 global $SPECIAL_VALUES,$aSessionVars,$aRawDataValues;
9908
9909 if (isset($SPECIAL_VALUES["multi_keep"]) &&
9910 !empty($SPECIAL_VALUES["multi_keep"]))
9911 {
9912 $a_list = TrimArray(explode(",",$SPECIAL_VALUES["multi_keep"]));
9913 if (!isset($aSessionVars["FormKeep"]))
9914 $aSessionVars["FormKeep"] = array();
9915 //
9916 // For each data field specified in "multi_keep" store its
9917 // value in the FormKeep session variable.
9918 // If a field is specified and does not exist in the
9919 // recent submission, its value is discarded.
9920 //
9921 foreach ($a_list as $s_fld_name)
9922 if (!empty($s_fld_name))
9923 if (isset($aRawDataValues[$s_fld_name]))
9924 $aSessionVars["FormKeep"][$s_fld_name] = $aRawDataValues[$s_fld_name];
9925 else
9926 unset($aSessionVars["FormKeep"][$s_fld_name]);
9927 }
9928}
9929
9930 //
9931 // Perform Logic for Multi-Page form sequences
9932 //
9933function MultiFormLogic()
9934{
9935 global $bMultiForm,$SPECIAL_VALUES,$aSessionVars,$aServerVars;
9936 global $sFormMailScript,$bGotGoBack,$bGotNextForm,$iFormIndex;
9937 global $aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues;
9938
9939 if ($SPECIAL_VALUES["multi_start"] == 1)
9940 {
9941 if (empty($SPECIAL_VALUES["this_form"]))
9942 Error("need_this_form",GetMessage(MSG_NEED_THIS_FORM),false,false);
9943
9944 $bMultiForm = true;
9945 //
9946 // Start of multi-page form sequence
9947 //
9948 $aSessionVars["FormList"] = array();
9949 $aSessionVars["FormList"][0] = array("URL"=>$SPECIAL_VALUES["this_form"],
9950 "ORDER"=>$aFieldOrder,
9951 "CLEAN"=>$aCleanedValues,
9952 "RAWDATA"=>$aRawDataValues,
9953 "ALLDATA"=>$aAllRawValues);
9954 $iFormIndex = $aSessionVars["FormIndex"] = 0; // zero is the first form, which was
9955 // just submitted
9956 }
9957 elseif (isset($aSessionVars["FormList"]))
9958 $bMultiForm = true;
9959
9960 if ($bMultiForm)
9961 {
9962 if (isset($aServerVars["PHP_SELF"]) &&
9963 !empty($aServerVars["PHP_SELF"]) &&
9964 isset($aServerVars["SERVER_NAME"]) &&
9965 !empty($aServerVars["SERVER_NAME"]))
9966 {
9967 if (isset($aServerVars["SERVER_PORT"]) &&
9968 $aServerVars["SERVER_PORT"] != 80)
9969 {
9970 if ($aServerVars["SERVER_PORT"] == 443) // SSL port
9971 //
9972 // just use https prefix
9973 //
9974 $sFormMailScript = "https://".$aServerVars["SERVER_NAME"].
9975 $aServerVars["PHP_SELF"];
9976 else
9977 //
9978 // use http with port number
9979 //
9980 $sFormMailScript = "http://".$aServerVars["SERVER_NAME"].
9981 ":".$aServerVars["SERVER_PORT"].
9982 $aServerVars["PHP_SELF"];
9983 }
9984 else
9985 $sFormMailScript = "http://".$aServerVars["SERVER_NAME"].
9986 $aServerVars["PHP_SELF"];
9987 $iFormIndex = $aSessionVars["FormIndex"];
9988 }
9989 else
9990 Error("no_php_self",GetMessage(MSG_NO_PHP_SELF),false,false);
9991 }
9992
9993 //
9994 // If we're going forward in a multi-page form sequence,
9995 // compute a URL to return to the form we're about to display.
9996 //
9997 if ($bMultiForm && !$bGotGoBack)
9998 {
9999 //
10000 // record the data that was just submitted by the previous form
10001 //
10002 $iFormIndex = $aSessionVars["FormIndex"];
10003 $aSessionVars["FormList"][$iFormIndex]["ORDER"] = $aFieldOrder;
10004 $aSessionVars["FormList"][$iFormIndex]["CLEAN"] = $aCleanedValues;
10005 $aSessionVars["FormList"][$iFormIndex]["RAWDATA"] = $aRawDataValues;
10006 $aSessionVars["FormList"][$iFormIndex]["ALLDATA"] = $aAllRawValues;
10007 $iFormIndex++;
10008 $s_url = GetReturnLink($sFormMailScript,$iFormIndex);
10009 $aSessionVars["FormList"][$iFormIndex] = array("URL"=>$s_url,
10010 "FORM"=>$SPECIAL_VALUES["next_form"],
10011 "ORDER"=>$aFieldOrder,
10012 "CLEAN"=>$aCleanedValues,
10013 "RAWDATA"=>$aRawDataValues,
10014 "ALLDATA"=>$aAllRawValues);
10015 $aSessionVars["FormIndex"] = $iFormIndex;
10016 MultiKeep();
10017 }
10018}
10019
10020 //
10021 // Check for the MIME Attack
10022 //
10023function DetectMimeAttack($a_fields,&$s_attack,&$s_info)
10024{
10025 //
10026 // if any of the recipient fields contain "MIME-Version" or
10027 // "Content-Type" then this is the MIME attack
10028 //
10029 $a_rec_flds = array("recipients","cc","bcc"); // all these fields must be scalar (not arrays)
10030 foreach ($a_rec_flds as $s_fld)
10031 if (isset($a_fields[$s_fld]) && is_scalar($a_fields[$s_fld]))
10032 {
10033 $s_data = strtolower($a_fields[$s_fld]);
10034 if (($i_mime = strpos($s_data,"mime-version")) !== false ||
10035 ($i_cont = strpos($s_data,"content-type")) !== false)
10036 {
10037 $s_attack = "MIME";
10038 $s_info = GetMessage(MSG_ATTACK_MIME_INFO,
10039 array("FLD"=>$s_fld,
10040 "CONTENT"=>($i_mime !== false) ?
10041 "mime-version" :
10042 "content-type"),false);
10043 return (true);
10044 }
10045 }
10046 return (false);
10047}
10048
10049 //
10050 // Check for the duplicate data attack
10051 //
10052function DetectDupAttack($a_fields,&$s_attack,&$s_info)
10053{
10054 //
10055 // if any of the configured fields contain duplicate data,
10056 // then this lame attack has been detected
10057 //
10058 global $ATTACK_DETECTION_DUPS;
10059
10060 $a_data_map = array();
10061 foreach ($ATTACK_DETECTION_DUPS as $s_fld)
10062 if (isset($a_fields[$s_fld]) &&
10063 is_scalar($a_fields[$s_fld]) && // can only work with string data
10064 !empty($a_fields[$s_fld]))
10065 {
10066 $s_data = (string) $a_fields[$s_fld];
10067 if (isset($a_data_map[$s_data]))
10068 {
10069 //
10070 // duplicate found!
10071 //
10072 $s_attack = "Duplicate Fields";
10073 $s_info = GetMessage(MSG_ATTACK_DUP_INFO,
10074 array("FLD1"=>$a_data_map[$s_data],
10075 "FLD2"=>$s_fld),false);
10076 return (true);
10077 }
10078 $a_data_map[$s_data] = $s_fld;
10079 }
10080 return (false);
10081}
10082
10083 //
10084 // Check for the email addresses in specials attack
10085 //
10086function DetectSpecialsAttack($a_fields,&$s_attack,&$s_info)
10087{
10088 //
10089 // look for email addresses in these special fields
10090 //
10091 $a_specs = array("derive_fields","required","mail_options",
10092 "good_url","bad_url","good_template","bad_template");
10093 foreach ($a_specs as $s_fld)
10094 {
10095 if (isset($a_fields[$s_fld]) &&
10096 is_scalar($a_fields[$s_fld]) && // can only work with string data
10097 !empty($a_fields[$s_fld]))
10098 {
10099 $s_data = $a_fields[$s_fld];
10100 if (preg_match("/^\b[-a-z0-9._%]+@[-.%_a-z0-9]+\.[a-z]{2,9}\b$/i",
10101 $s_data) === 1)
10102 {
10103 //
10104 // email address found in wrong field
10105 //
10106 $s_attack = "Special Fields";
10107 $s_info = GetMessage(MSG_ATTACK_SPEC_INFO,
10108 array("FLD"=>$s_fld),false);
10109 return (true);
10110 }
10111 }
10112 }
10113 return (false);
10114}
10115
10116 //
10117 // Detect annoying attacks and prevent them from sending spurious
10118 // alert messages.
10119 //
10120function DetectAttacks($a_fields)
10121{
10122 global $ATTACK_DETECTION_DUPS;
10123
10124 $s_info = $s_attack = "";
10125 $b_attacked = false;
10126 if (ATTACK_DETECTION_MIME)
10127 if (DetectMimeAttack($a_fields,$s_attack,$s_info))
10128 $b_attacked = true;
10129 if (!$b_attacked && !empty($ATTACK_DETECTION_DUPS))
10130 if (DetectDupAttack($a_fields,$s_attack,$s_info))
10131 $b_attacked = true;
10132 if (!$b_attacked && ATTACK_DETECTION_SPECIALS)
10133 if (DetectSpecialsAttack($a_fields,$s_attack,$s_info))
10134 $b_attacked = true;
10135
10136 if ($b_attacked)
10137 {
10138 if (ALERT_ON_ATTACK_DETECTION)
10139 SendAlert(GetMessage(MSG_ATTACK_DETECTED,
10140 array("ATTACK"=>$s_attack,
10141 "INFO"=>$s_info,)),
10142 false);
10143 CreatePage(GetMessage(MSG_ATTACK_PAGE));
10144 exit;
10145 }
10146}
10147
10148if (isset($aGetVars["return"]) && is_numeric($aGetVars["return"]))
10149{
10150 MultiFormReturn($aGetVars["return"]);
10151 exit;
10152}
10153
10154 //
10155 // Hook system: after initialization
10156 //
10157if ($HOOK_DIR !== "")
10158 @include("$HOOK_DIR/fmhookpostinit.inc");
10159
10160 //
10161 // check configuration values for potential security problems
10162 //
10163CheckConfig();
10164
10165 //
10166 // otherwise, do the real processing of FormMail
10167 //
10168$aStrippedFormVars = $aAllRawValues = StripGPCArray($aFormVars);
10169
10170if (ENABLE_ATTACK_DETECTION)
10171 DetectAttacks($aAllRawValues);
10172
10173 //
10174 // process the options
10175 //
10176ProcessMailOptions($aAllRawValues);
10177ProcessCRMOptions($aAllRawValues);
10178ProcessAROptions($aAllRawValues);
10179ProcessFilterOptions($aAllRawValues);
10180
10181 //
10182 // create any derived fields
10183 //
10184$aAllRawValues = CreateDerived($aAllRawValues);
10185
10186list($aFieldOrder,$aCleanedValues,$aRawDataValues) = ParseInput($aAllRawValues);
10187
10188 //
10189 // if we're processing multi-forms, then merge in the raw data from previous
10190 // forms
10191 //
10192if (isset($aSessionVars["FormList"]))
10193{
10194 list($aFieldOrder,$aCleanedValues,
10195 $aRawDataValues,$aAllRawValues) = GetMultiValues(
10196 $aSessionVars["FormList"],
10197 $aSessionVars["FormIndex"],
10198 $aFieldOrder,$aCleanedValues,
10199 $aRawDataValues,$aAllRawValues);
10200}
10201
10202if ($SPECIAL_VALUES["file_names"] !== "")
10203 list($aFieldOrder,$aCleanedValues,$aRawDataValues,$aFileVars) =
10204 SetFileNames($SPECIAL_VALUES["file_names"],$aFieldOrder,
10205 $aCleanedValues,$aRawDataValues,$aFileVars);
10206
10207 //
10208 // Hook system: after loading and processing data
10209 //
10210if ($HOOK_DIR !== "")
10211 @include("$HOOK_DIR/fmhookload.inc");
10212
10213if ($FORM_INI_FILE !== "")
10214{
10215 ProcessFormIniFile($FORM_INI_FILE);
10216 //
10217 // Hook system: after processing INI file
10218 //
10219 if ($HOOK_DIR !== "")
10220 @include("$HOOK_DIR/fmhookinifile.inc");
10221}
10222
10223$bDoneSomething = false;
10224if (DB_SEE_INPUT)
10225{
10226 CreatePage(implode("\n",$FORMATTED_INPUT));
10227 ZapSession();
10228 exit;
10229}
10230
10231if (isset($SPECIAL_VALUES["multi_go_back"]) && !empty($SPECIAL_VALUES["multi_go_back"]))
10232{
10233 if (!isset($aSessionVars["FormList"]) || $aSessionVars["FormIndex"] == 0)
10234 Error("go_back",GetMessage(MSG_GO_BACK),false,false);
10235 MultiKeep(); // store any "multi_keep" data just submitted
10236 MultiFormReturn($aSessionVars["FormIndex"]-1);
10237// echo "Form index = ".$aSessionVars["FormIndex"];
10238 exit;
10239}
10240
10241 //
10242 // This is the check for spiders; I can't imagine a spider will
10243 // ever use the POST method.
10244 //
10245if ($bIsGetMethod && count($aFormVars) == 0)
10246{
10247 CreatePage(GetMessage(MSG_NO_DATA_PAGE));
10248 ZapSession();
10249 exit;
10250}
10251
10252 //
10253 // Hook system: before performing required and conditions etc.
10254 //
10255if ($HOOK_DIR !== "")
10256 @include("$HOOK_DIR/fmhookprechecks.inc");
10257
10258 //
10259 // check for required fields
10260 //
10261if (!CheckRequired($SPECIAL_VALUES["required"],$aAllRawValues,$missing,$a_missing_list))
10262 UserError("missing_fields",GetMessage(MSG_REQD_ERROR),$missing,$a_missing_list);
10263
10264 //
10265 // check complex conditions
10266 //
10267if (!CheckConditions($SPECIAL_VALUES["conditions"],$aAllRawValues,$missing,$a_missing_list))
10268 UserError("failed_conditions",GetMessage(MSG_COND_ERROR),$missing,$a_missing_list);
10269
10270 //
10271 // check imgverify
10272 //
10273if (isset($SPECIAL_VALUES["imgverify"]) && !empty($SPECIAL_VALUES["imgverify"]))
10274{
10275 if (!isset($aSessionVars["VerifyImgString"]))
10276 Error("verify_failed",GetMessage(MSG_VERIFY_MISSING),false);
10277 //
10278 // the user's entry must match the value in the session; allow
10279 // spaces in the user's input
10280 //
10281 if (str_replace(" ","",$SPECIAL_VALUES["imgverify"]) !==
10282 $aSessionVars["VerifyImgString"])
10283 UserError("img_verify",GetMessage(MSG_VERIFY_MATCH));
10284}
10285
10286 //
10287 // Hook system: after performing required and conditions etc.
10288 //
10289if ($HOOK_DIR !== "")
10290 @include("$HOOK_DIR/fmhookchecks.inc");
10291
10292if (!empty($SPECIAL_VALUES["fmcompute"]))
10293{
10294 $FM_UserErrors = array();
10295 //
10296 // Generalized interface between FMCompute and FormMail functions
10297 //
10298 function FM_CallFunction($s_func,$a_params,$m_return,
10299 &$s_mesg,&$a_debug,&$a_alerts)
10300 {
10301 switch ($s_func)
10302 {
10303 case "FMFatalError":
10304 if (count($a_params) < 3)
10305 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
10306 array("FUNC"=>$s_func,
10307 "COUNT"=>count($a_params))),
10308 false,false);
10309 else
10310 Error("fmcompute_error",$a_params[0],$a_params[1],$a_params[2]);
10311 break;
10312
10313 case "FMFatalUserError":
10314 if (count($a_params) < 1)
10315 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
10316 array("FUNC"=>$s_func,
10317 "COUNT"=>count($a_params))),
10318 false,false);
10319 else
10320 UserError("fmcompute_usererror",$a_params[0]);
10321 break;
10322
10323 case "FMUserError":
10324 if (count($a_params) < 1)
10325 Error("fmcompute_call",GetMessage(MSG_CALL_PARAM_COUNT,
10326 array("FUNC"=>$s_func,
10327 "COUNT"=>count($a_params))),
10328 false,false);
10329 else
10330 {
10331 global $FM_UserErrors;
10332
10333 $FM_UserErrors[] = $a_params[0];
10334 }
10335 break;
10336
10337 default:
10338 $s_mesg = GetMessage(MSG_CALL_UNK_FUNC,array("FUNC"=>$s_func));
10339 return (false);
10340 }
10341 return (true);
10342 }
10343
10344 //
10345 // register useful FormMail functions with FMCompute module
10346 //
10347 function RegisterFormMailFunctions(&$fmc)
10348 {
10349 //
10350 // Allows the user to call "Error" from within a computation
10351 //
10352 if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
10353 "FMFatalError",
10354 array("string","bool","bool"),
10355 "FM_CallFunction")) !== true)
10356 Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
10357 array("FUNC"=>"FMFatalError",
10358 "ERROR"=>$s_msg)),false,false);
10359 //
10360 // Allows the user to call "UserError" from within a computation
10361 //
10362 if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
10363 "FMFatalUserError",
10364 array("string"),
10365 "FM_CallFunction")) !== true)
10366 Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
10367 array("FUNC"=>"FMFatalUserError",
10368 "ERROR"=>$s_msg)),false,false);
10369
10370 //
10371 // Allows the user to record an error to be displayed
10372 // from within a computation.
10373 //
10374 if (($s_msg = $fmc->RegisterExternalFunction("PHP","void",
10375 "FMUserError",
10376 array("string"),
10377 "FM_CallFunction")) !== true)
10378 Error("fmcompute_reg",GetMessage(MSG_REG_FMCOMPUTE,
10379 array("FUNC"=>"FMUserError",
10380 "ERROR"=>$s_msg)),false,false);
10381 }
10382
10383 //
10384 // load the fmcompute module
10385 //
10386 $FMCOMPUTE_CLASS = true;
10387 $FMCOMPUTE_NODEBUG = true;
10388 if (!include_once("$MODULEDIR/$FMCOMPUTE"))
10389 Error("load_fmcompute",GetMessage(MSG_LOAD_FMCOMPUTE,
10390 array("FILE"=>"$MODULEDIR/$FMCOMPUTE",
10391 "ERROR"=>$php_errormsg)),false,false);
10392 RegisterFormMailFunctions($FMCalc);
10393
10394 //
10395 // if GeoIP support is specified, load that module now
10396 //
10397 if (!empty($GEOIP_LIC))
10398 {
10399 $FMMODULE_LOAD = true; // signal module load
10400 if (!include_once("$MODULEDIR/$FMGEOIP"))
10401 Error("load_module",GetMessage(MSG_LOAD_MODULE,
10402 array("FILE"=>"$MODULEDIR/$FMGEOIP",
10403 "ERROR"=>$php_errormsg)),false,false);
10404 //
10405 // load the license and register the module
10406 //
10407 $GeoIP = new FMGeoIP($GEOIP_LIC);
10408 if (!$GeoIP->RegisterModule($FMCalc))
10409 Error("reg_module",GetMessage(MSG_REGISTER_MODULE,
10410 array("NAME"=>"FMGeoIP",
10411 "ERROR"=>$GeoIP->GetError())),false,false);
10412 }
10413}
10414
10415if (!empty($SPECIAL_VALUES["fmmodules"]))
10416{
10417 $aModuleList = TrimArray(explode(",",$SPECIAL_VALUES["fmmodules"]));
10418 $FMMODULE_LOAD = true; // signal module load
10419 foreach ($aModuleList as $sModule)
10420 if (!include_once("$MODULEDIR/$sModule"))
10421 Error("load_module",GetMessage(MSG_LOAD_MODULE,
10422 array("FILE"=>"$MODULEDIR/$sModule",
10423 "ERROR"=>$php_errormsg)),false,false);
10424}
10425
10426if (!empty($SPECIAL_VALUES["fmcompute"]))
10427{
10428 //
10429 // Callback function for preg_replace_callback to add line
10430 // numbers on each match
10431 //
10432 function AddLineNumbersCallback($a_matches)
10433 {
10434 global $iAddLineNumbersCounter;
10435
10436 return (sprintf("%d:",++$iAddLineNumbersCounter).$a_matches[0]);
10437 }
10438 //
10439 // Add line numbers to some code
10440 //
10441 function AddLineNumbers($s_code)
10442 {
10443 global $iAddLineNumbersCounter;
10444
10445 $iAddLineNumbersCounter = 0;
10446 return (preg_replace_callback('/^/m','AddLineNumbersCallback',$s_code));
10447 }
10448
10449 //
10450 // Load some more code into FMCalc
10451 //
10452 function Load($s_code)
10453 {
10454 global $FMCalc;
10455
10456 $a_mesgs = array();
10457 // echo "Loading '$s_code'";
10458 if ($FMCalc->Parse($s_code,$a_mesgs) === false)
10459 {
10460 $s_msgs = "";
10461 foreach ($a_mesgs as $a_msg)
10462 {
10463 $s_msgs .= "Line ".$a_msg["LINE"];
10464 $s_msgs .= ", position ".$a_msg["CHAR"].": ";
10465 $s_msgs .= $a_msg["MSG"]."\n";
10466 }
10467 Error("fmcompute_parse",GetMessage(MSG_COMP_PARSE,
10468 array("CODE"=>AddLineNumbers($s_code),
10469 "ERRORS"=>$s_msgs)),false,false);
10470 }
10471 }
10472
10473 //
10474 // Send any alerts found in FMCalc
10475 //
10476 function SendComputeAlerts()
10477 {
10478 global $FMCalc;
10479
10480 $a_alerts = $FMCalc->GetAlerts();
10481 if (count($a_alerts) > 0)
10482 SendAlert(GetMessage(MSG_COMP_ALERT,
10483 array("ALERTS"=>implode("\n",$a_alerts))));
10484 $a_debug = $FMCalc->GetDebug();
10485 if (count($a_debug) > 0)
10486 SendAlert(GetMessage(MSG_COMP_DEBUG,
10487 array("DEBUG"=>implode("\n",$a_debug))));
10488 }
10489 //
10490 // Perform the computations in FMCalc
10491 //
10492 function Compute(&$a_field_order,&$a_cleaned_values,&$a_raw_data_values,
10493 &$a_values)
10494 {
10495 global $FMCalc,$FM_UserErrors;
10496
10497 $a_mesgs = array();
10498 $FM_UserErrors = array();
10499 if (($a_flds = $FMCalc->Execute($a_mesgs)) !== false)
10500 {
10501 SendComputeAlerts();
10502 foreach ($a_flds as $s_name=>$s_value)
10503 {
10504 $a_values[$s_name] = $s_value;
10505 ProcessField($s_name,$s_value,$a_field_order,
10506 $a_cleaned_values,$a_raw_data_values);
10507 }
10508 if (count($FM_UserErrors) > 0)
10509 UserError("fmcompute_usererrors",GetMessage(MSG_USER_ERRORS),
10510 "",$FM_UserErrors);
10511 }
10512 else
10513 {
10514 SendComputeAlerts();
10515 Error("fmcompute_exec",GetMessage(MSG_COMP_EXEC,
10516 array("ERRORS"=>implode("\n",$a_mesgs))),false,false);
10517 }
10518 }
10519
10520 //
10521 // Register all fields; a future improvement should use a call-back
10522 // function so as not to copy all the data into the FMCompute object
10523 //
10524 function RegisterData($a_form_data)
10525 {
10526 global $FMCalc;
10527
10528 foreach ($a_form_data as $s_name=>$s_value)
10529 if (isset($s_name) && isset($s_value))
10530 if (($s_msg = $FMCalc->RegisterExternalData("PHP","string",
10531 $s_name,"c",$s_value)) !== true)
10532 Error("fmcompute_regdata",GetMessage(MSG_COMP_REG_DATA,
10533 array("NAME"=>$s_name,"ERROR"=>$s_msg)),false,false);
10534
10535
10536 }
10537 RegisterData($aAllRawValues);
10538 //
10539 // parse all fmcompute fields
10540 //
10541 if (is_array($SPECIAL_VALUES["fmcompute"]))
10542 {
10543 $nCompute = count($SPECIAL_VALUES["fmcompute"]);
10544 for ($iCompute = 0 ; $iCompute < $nCompute ; $iCompute++)
10545 Load($SPECIAL_VALUES["fmcompute"][$iCompute]);
10546 }
10547 else
10548 Load($SPECIAL_VALUES["fmcompute"]);
10549
10550 //
10551 // run computations
10552 //
10553 Compute($aFieldOrder,$aCleanedValues,$aRawDataValues,$aAllRawValues);
10554 //
10555 // Hook system: after computations
10556 //
10557 if ($HOOK_DIR !== "")
10558 @include("$HOOK_DIR/fmhookcompute.inc");
10559}
10560
10561$bGotGoBack = $bGotNextForm = $bGotGoodTemplate = $bGotGoodUrl = false;
10562if (isset($SPECIAL_VALUES["good_url"]) &&
10563 !empty($SPECIAL_VALUES["good_url"]))
10564 $bGotGoodUrl = true;
10565
10566if (isset($SPECIAL_VALUES["good_template"]) &&
10567 !empty($SPECIAL_VALUES["good_template"]))
10568 $bGotGoodTemplate = true;
10569
10570if (isset($SPECIAL_VALUES["next_form"]) &&
10571 !empty($SPECIAL_VALUES["next_form"]))
10572 $bGotNextForm = true;
10573
10574if (isset($SPECIAL_VALUES["multi_go_back"]) &&
10575 !empty($SPECIAL_VALUES["multi_go_back"]))
10576 $bGotGoBack = true;
10577
10578 //
10579 // it's not valid to specify "next_form" as well as "good_url" or
10580 // "good_template"; this is because it's ambiguous - do we go to the
10581 // next form or the final 'thank you' page?
10582 //
10583if ($bGotNextForm && ($bGotGoodTemplate || $bGotGoodUrl))
10584 Error("next_plus_good",GetMessage(MSG_NEXT_PLUS_GOOD,array("WHICH"=>
10585 ($bGotGoodUrl ? "good_url" :
10586 "good_template"))),false,false);
10587
10588MultiFormLogic();
10589
10590 //
10591 // Hook system: after multi-page form logic
10592 //
10593if ($HOOK_DIR !== "")
10594 @include("$HOOK_DIR/fmhookmulti.inc");
10595
10596 //
10597 // write to the CSV database
10598 //
10599if (!empty($CSVDIR) && isset($SPECIAL_VALUES["csvfile"]) &&
10600 !empty($SPECIAL_VALUES["csvfile"]))
10601{
10602 //
10603 // Hook system: before writing CSV file
10604 //
10605 if ($HOOK_DIR !== "")
10606 @include("$HOOK_DIR/fmhookprecsv.inc");
10607 WriteCSVFile($CSVDIR."/".basename($SPECIAL_VALUES["csvfile"]),$aAllRawValues);
10608 //
10609 // Hook system: after writing CSV file
10610 //
10611 if ($HOOK_DIR !== "")
10612 @include("$HOOK_DIR/fmhookpostcsv.inc");
10613 $bDoneSomething = true;
10614}
10615
10616 //
10617 // write to the log file
10618 //
10619if (!empty($LOGDIR) && isset($SPECIAL_VALUES["logfile"]) && !empty($SPECIAL_VALUES["logfile"]))
10620{
10621 //
10622 // Hook system: before writing log file
10623 //
10624 if ($HOOK_DIR !== "")
10625 @include("$HOOK_DIR/fmhookprelog.inc");
10626 WriteLog($LOGDIR."/".basename($SPECIAL_VALUES["logfile"]));
10627 //
10628 // Hook system: after writing log file
10629 //
10630 if ($HOOK_DIR !== "")
10631 @include("$HOOK_DIR/fmhookpostlog.inc");
10632 $bDoneSomething = true;
10633}
10634
10635 //
10636 // send to the CRM
10637 //
10638if (isset($SPECIAL_VALUES["crm_url"]) && isset($SPECIAL_VALUES["crm_spec"]))
10639{
10640 $sCRM = GetCRMURL($SPECIAL_VALUES["crm_spec"],$aAllRawValues,$SPECIAL_VALUES["crm_url"]);
10641 if (!empty($sCRM))
10642 {
10643 $aCRMReturnData = array();
10644 //
10645 // Hook system: before sending to CRM
10646 //
10647 if ($HOOK_DIR !== "")
10648 @include("$HOOK_DIR/fmhookprecrm.inc");
10649 if (!SendToCRM($sCRM,$aCRMReturnData))
10650 {
10651 //
10652 // CRM interface failed, check if the form wants an error
10653 // displayed
10654 //
10655 if (IsCRMOptionSet("ErrorOnFail"))
10656 Error("crm_failed",GetMessage(MSG_CRM_FAILURE));
10657 }
10658 else
10659 //
10660 // append the returned data to the raw data values of the form
10661 //
10662 $aRawDataValues = array_merge($aRawDataValues,$aCRMReturnData);
10663 //
10664 // Hook system: after sending to CRM
10665 //
10666 if ($HOOK_DIR !== "")
10667 @include("$HOOK_DIR/fmhookpostcrm.inc");
10668 $bDoneSomething = true;
10669 }
10670}
10671
10672 //
10673 // Check obsolete SendMailFOption
10674 //
10675if (IsMailOptionSet("SendMailFOption"))
10676 SendAlert(GetMessage(MSG_FOPTION_WARN,array("LINE"=>SENDMAIL_F_OPTION_LINE)),
10677 false,true);
10678
10679 //
10680 // send email
10681 //
10682if (!isset($SPECIAL_VALUES["recipients"]) || empty($SPECIAL_VALUES["recipients"]))
10683{
10684 //
10685 // No recipients - don't email anyone...
10686 // If nothing has been done above (CSV, logging, or CRM),
10687 // then report an error.
10688 //
10689 if (!$bDoneSomething)
10690 if (!$bGotGoBack && !$bGotNextForm)
10691 Error("no_recipients",GetMessage(MSG_NO_ACTIONS));
10692}
10693else
10694{
10695 //
10696 // Hook system: before sending emails
10697 //
10698 if ($HOOK_DIR !== "")
10699 @include("$HOOK_DIR/fmhookpreemail.inc");
10700 $s_invalid = $s_invalid_cc = $s_invalid_bcc = "";
10701 if (!CheckEmailAddress($SPECIAL_VALUES["recipients"],$s_valid_recipients,$s_invalid))
10702 Error("no_valid_recipients",GetMessage(MSG_NO_RECIP));
10703 else
10704 {
10705 $s_valid_cc = $s_valid_bcc = "";
10706
10707 //
10708 // check CC and BCC addresses
10709 //
10710 if (isset($SPECIAL_VALUES["cc"]) && !empty($SPECIAL_VALUES["cc"]))
10711 CheckEmailAddress($SPECIAL_VALUES["cc"],$s_valid_cc,$s_invalid_cc);
10712 if (isset($SPECIAL_VALUES["bcc"]) && !empty($SPECIAL_VALUES["bcc"]))
10713 CheckEmailAddress($SPECIAL_VALUES["bcc"],$s_valid_bcc,$s_invalid_bcc);
10714
10715 //
10716 // send an alert for invalid addresses
10717 //
10718 $s_error = "";
10719 if (!empty($s_invalid))
10720 $s_error .= "recipients: $s_invalid\r\n";
10721 if (!empty($s_invalid_cc))
10722 $s_error .= "cc: $s_invalid_cc\r\n";
10723 if (!empty($s_invalid_bcc))
10724 $s_error .= "bcc: $s_invalid_bcc\r\n";
10725 if (!empty($s_error))
10726 SendAlert(GetMessage(MSG_INV_EMAIL,array("ERRORS"=>$s_error)));
10727
10728 //
10729 // send the actual results
10730 //
10731 if (!SendResults($aFieldOrder,$aCleanedValues,$s_valid_recipients,$s_valid_cc,
10732 $s_valid_bcc,$aRawDataValues))
10733 Error("mail_failed",GetMessage(MSG_FAILED_SEND));
10734 //
10735 // Hook system: after sending emails
10736 //
10737 if ($HOOK_DIR !== "")
10738 @include("$HOOK_DIR/fmhookpostemail.inc");
10739 }
10740}
10741
10742 //
10743 // if the user didn't enter the verification code,
10744 // just skip the autoresponse
10745 //
10746if (isset($SPECIAL_VALUES["arverify"]) && !empty($SPECIAL_VALUES["arverify"]))
10747 if (IsAROptionSet('HTMLTemplate') || IsAROptionSet('PlainTemplate'))
10748 {
10749 if (!isset($SPECIAL_VALUES["email"]) || empty($SPECIAL_VALUES["email"]))
10750 SendAlert(GetMessage(MSG_ARESP_EMAIL));
10751 else
10752 {
10753 //
10754 // Hook system: before sending auto response
10755 //
10756 if ($HOOK_DIR !== "")
10757 @include("$HOOK_DIR/fmhookprearesp.inc");
10758 $sAutoRespTo = $SPECIAL_VALUES["email"];
10759 if (IsAROptionSet('Subject'))
10760 $sAutoRespSubj = GetAROption('Subject');
10761 else
10762 $sAutoRespSubj = GetMessage(MSG_ARESP_SUBJ,array(),false);
10763
10764 if (!isset($aSessionVars["VerifyImgString"]))
10765 {
10766 WriteARLog($sAutoRespTo,$sAutoRespSubj,
10767 GetMessage(MSG_LOG_NO_VERIMG,array(),false));
10768 Error("verify_failed",GetMessage(MSG_ARESP_NO_AUTH),true);
10769 }
10770 //
10771 // the user's entry must match the value in the session; allow
10772 // spaces in the user's input
10773 //
10774 if (str_replace(" ","",$SPECIAL_VALUES["arverify"]) !==
10775 $aSessionVars["VerifyImgString"])
10776 {
10777 WriteARLog($sAutoRespTo,$sAutoRespSubj,
10778 GetMessage(MSG_LOG_NO_MATCH,array(),false));
10779 UserError("ar_verify",GetMessage(MSG_ARESP_NO_MATCH));
10780 }
10781 elseif (!AutoRespond($sAutoRespTo,$sAutoRespSubj,$aRawDataValues))
10782 {
10783 WriteARLog($sAutoRespTo,$sAutoRespSubj,
10784 GetMessage(MSG_LOG_FAILED,array(),false));
10785 SendAlert(GetMessage(MSG_ARESP_FAILED));
10786 }
10787 else
10788 {
10789 WriteARLog($sAutoRespTo,$sAutoRespSubj,
10790 GetMessage(MSG_LOG_OK,array(),false));
10791 //
10792 // Hook system: after sending auto response
10793 //
10794 if ($HOOK_DIR !== "")
10795 @include("$HOOK_DIR/fmhookpostaresp.inc");
10796 }
10797 }
10798 }
10799
10800 //
10801 // multi-form processing
10802 //
10803if ($bGotNextForm)
10804{
10805 OutputMultiFormTemplate($SPECIAL_VALUES["next_form"],$aRawDataValues);
10806// echo "Form index = ".$aSessionVars["FormIndex"];
10807}
10808else
10809{
10810 //
10811 // Hook system: before finishing
10812 //
10813 if ($HOOK_DIR !== "")
10814 @include("$HOOK_DIR/fmhookprefinish.inc");
10815 //
10816 // redirect to the good URL page, or create a default page;
10817 // we're no longer processing a multi-page form sequence
10818 //
10819 unset($aSessionVars["FormList"]);
10820 unset($aSessionVars["FormIndex"]);
10821 unset($aSessionVars["FormKeep"]);
10822 if (!$bGotGoodUrl)
10823 {
10824 if ($bGotGoodTemplate)
10825 OutputTemplate($SPECIAL_VALUES["good_template"],$aRawDataValues);
10826 else
10827 CreatePage(GetMessage(MSG_THANKS_PAGE));
10828 }
10829 else
10830 Redirect($SPECIAL_VALUES["good_url"]);
10831 //
10832 // Hook system: after finishing (before session is cleared)
10833 //
10834 if ($HOOK_DIR !== "")
10835 @include("$HOOK_DIR/fmhookpostfinish.inc");
10836 //
10837 // everything's good, so we don't need the session any more
10838 //
10839 ZapSession();
10840}
10841?>
10842