Nähere Informationen folgen in Kürze.
+Über die Referentin: https://www.germanistik.uni-rostock.de/personen/professuren/jun-prof-dr-ulrike-henny-krahmer/
+diff --git a/Dockerfile.nginx b/Dockerfile.nginx index b922fcd5..e0421166 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -2,7 +2,7 @@ # Use the nginx Dockerfile for the static site (when the registration is closed) # and the apache Dockerfile (with php enabled) for the php registration form -FROM jekyll/builder as builder +FROM jekyll/builder AS builder ENV WORK_DIR=/var/jekyllbuilder diff --git a/_archiv/2025/classes/Keynote.html b/_archiv/2025/classes/Keynote.html new file mode 100644 index 00000000..af041bfc --- /dev/null +++ b/_archiv/2025/classes/Keynote.html @@ -0,0 +1,19 @@ +--- +title: "tba" +title-short: Keynote +label: keynote +lang: deutsch +costs: 0 +teachers: +- Jun.-Prof. Dr. Ulrike Henny-Krahmer +target-audience: Alle Interessierten +slots: +- Mo5 + +room: Foyer +--- + +
Nähere Informationen folgen in Kürze.
+Über die Referentin: https://www.germanistik.uni-rostock.de/personen/professuren/jun-prof-dr-ulrike-henny-krahmer/
+Neben dem Kursangebot lebt die ESS vom Netzwerken und vor allem auch vom fachlichen Austausch. Ein niederschwelliges Format dafür ist unsere Poster-Session am Dienstagabend. Hier gibt es die Möglichkeit andere Forschende auf die eigene Arbeit aufmerksam zu machen und auch eigene Ideen zu diskutieren. Die Poster bleiben über die gesamte ESS ausgestellt, sodass eine breite Rezeptionsfläche entsteht.
+Wir freuen uns, wenn Sie bei der Poster-Session ein Projekt, Tool oder eine Forschungsarbeit vorstellen möchten. Bitte schicken Sie uns hierfür eine kurze Vorstellung Ihres Posters (max. eine halbe Seite) bis zum 15. August an ess@edirom.de. Wir informieren Sie bis 1. September, ob wir Ihren Beitrag annehmen.
+Neben der Ausstellung während der ESS würden wir die Poster gerne bei Zenodo veröffentlichen, sofern Sie damit einverstanden sind. Hierzu wird es separate Informationen nach der Anmeldung bzw. Annahme Ihres Beitrags geben.
+
Beethovens Werkstatt has come up with a sophisticated approach to diplomatic transcriptions based on MEI. The level of visual detail encoded goes well + beyond the current state of art. In this course, participants will get introduced to the data model and workflows of the project, and will discuss + its applicability for other cases. They will also explore different visualizations and export options to other data models like MEI Basic.
+Participants are expected to have a solid understanding of MEI, and the course will touch technical topics such as Javascript, XSLT, ODD and + Schematron. While no strong expertise in all these fields is expected from all participants, it will also not be possible to cover them in sufficient + detail for those without prior experience.
+The course will be given in German and English in parallel.
+ +Im Rahmen von Beethovens Werkstatt wurde ein komplexes Modell zur diplomatischen Transkription basierend auf MEI entwickelt. Der Detailgrad dieses + Modells insbesondere hinsichtlich der Präzision der diplomatischen Wiedergabe der Quellen geht dabei weit über etablierte digitale Verfahren hinaus. + In diesem Kurs werden die Teilnehmenden mit dem Datenmodell und den diesbezüglichen Workflows des Projekts vertraut gemacht und die Übertragbarkeit + auf andere Beispiele diskutiert. Weiterhin werden verschiedene Visualisierungen und Exportoptionen zu anderen Datenmodellen wie MEI Basic erprobt.
+Die Teilnehmenden sollten solide Vorkenntnisse im Bereich MEI haben. Der Kurs wird weiterhin technische Themen wie Javascript, XSLT, ODD und Schematron + behandeln. Es werden keine ausgeprägten Vorkenntnisse in sämtlichen dieser Bereiche erwartet. Gleichzeitig wird es nicht möglich sein, all diese + Themen im Rahmen des Kurses von Grund auf zu lernen.
+Der Kurs wird parallel in Deutsch und Englisch angeboten.
+This hands-on workshop introduces participants to Docker, the leading containerization platform used by developers and operations teams to build, ship, and run applications in isolated environments. Aimed at beginners, this session covers essential concepts such as images, containers, Dockerfiles, and volumes. Attendees will learn how to use existing Docker images for their work and how to containerize a simple application themselves. + Through practical examples and guided exercises, participants will explore key Docker concepts including the client-server architecture, container lifecycle, image creation, volume management, and basic networking and commands. By the end of the workshop, participants will be equipped with the foundational knowledge needed to start using Docker in real-world development workflows. +
+ +This introductory course offers a hands-on overview of Edirom-Online, a web-based publication environment for digital music editions. Participants will learn about the core functionalities of the software, its typical fields of application, and how it supports the display and interaction of scholarly-critical music editions in digital form.
+ +In addition to exploring Edirom Online’s features, the course will guide participants through the workflow of preparing data for use within the system. This includes working with relevant encoding formats and external tools commonly used in digital editing projects. No prior experience with Edirom tools is required.
+ +The course is offered in the context of the recent 1.0.0 release of Edirom-Online, a milestone following several years of community-driven development. and will be led by the team of the “Edirom Online Reloaded” project, which has been working on modernizing the software since 2024.
+ +Die Arbeit mit digitalen Methoden, Werkzeugen und Daten bestimmt mehr und mehr den Alltag auch in musikwissenschaftlichen und editorischen Forschungsvorhaben. Die Organisation und das "Management" dieser Prozesse und Daten unterstützt uns bei der Arbeit und erleichtert die Nachvollziehbarkeit und die Nachnutzung der Forschung. Am Beispiel der Workflows und Datenpublikationen des OPEN Edirom Projekts werden Aspekte des Forschungsdatenmanagements verdeutlicht. Diese reichen von der Planung eines Vorhabens mit Hilfe von Datenmanagementplänen über Methoden und Werkzeuge der Datenorganisation bis hin zu Strategien der Veröffentlichung und Lizenzierung von Forschungsergebnisssen.
+ +Im Rahmen des Kurses werden wesentliche Konzepte des Forschungsdatenmanagements praxisnah erläutert. Für die Erstellung von Datenmanagementplänen wird das Werkzeug Research Data Managament Organiser (RDMO) vorgestellt und an einem Praxisbeispiel erprobt. Es werden die FAIR-Kriterien erläutert und Konzepte der Datenorganisation, Publikation und Archivierung vorgestellt. Lizenzen und weitere rechtliche Aspekte werden thematisiert und besprochen. Indem der Kurs "Forschungsdatenmanagement" relativ umfassend zum Thema hat, ist er nicht nur für Kolleg:innen im Bereich editorischer Projekte von Interesse.
+ +Gerne können Fragen, Anregungen, eigene Beispiele und Bedarfe mit in den Kurs eingebracht werden.
+Systeme zur Versionskontrolle sind mittlerweile für alle Forschenden von essentieller Bedeutung.
+Ein Versionskontrollsystem wie zum Beispiel git kann bei der Verwaltung von Forschungsdaten oder auch dem kollaborativen Schreiben an wissenschaftlichen Arbeiten genutzt werden. Es erlaubt nicht nur das koordinierte Arbeiten im Team, auch für den Einzelnen bietet z.B. die Bearbeitungshistorie einen deutlichen Vorteil. Nicht zuletzt können Forschungsergebnisse auf einer Online-Plattform wie GitHub oder GitLab nachnutzenden Wissenschaftler*innen oder der Öffentlichkeit zugänglich gemacht werden. Durch die Versionshistorie kann so auch die Nachvollziehbarkeit und Reproduzierbarkeit dieser Forschungsergebnisse verbessert werden.
+Im Rahmen des Kurses werden anhand eines kleinen Praxisbeispiels die Grundfunktionalitäten von git erklärt und gemeinsam praktisch umgesetzt. Es wird vermittelt, wie ein Repository angelegt wird, das Repository nach dem GitFlow-Modell strukturiert wird, Modifikationen an den Daten eingespielt und Konflikte gelöst werden. Dabei werden vor allem die Besonderheiten bei der Arbeit mit geisteswissenschaftlichen Daten und beim wissenschaftlichem Schreiben in git besprochen.
+Der MEI-Einführungskurs richtet sich an MEI-Neulinge gleichermaßen wie an Teilnehmer*innen, die bereits Erfahrungen mit dem Format haben. Ein grundlegendes Verständnis von Musiknotation wird vorausgesetzt. Der Kurs umfasst eine Einführung in die Codierung von Musiknotation mit MEI und dem damit verbundenen Prinzip von XML. Daneben wird eine grundlegende Einführung in die Metadaten-Codierung und in den Aufbau des MEI-Headers gegeben. Dabei sollen praktische Erfahrungen gesammelt und spezielle Anwendungen und Codierungsbeispiele erprobt und diskutiert werden. Gerne dürfen auch eigene Beispiele mitgebracht werden.
+Als Vorbereitung für den Kurs ist es empfehlenswert, sich auf den Seiten der Music Encoding Initiative über das Arbeiten mit MEI zu informieren und mit den MEI-Tutorials zu beschäftigen. Darüber hinaus wird darum gebeten, einen eigenen Laptop mitzubringen. Ebenso ist vor Beginn des Kurses die kostenlose Demoversion des XML-Editors oXygen zu installieren, um eine einheitliche Ausgangssituation zu gewährleisten.
++ ODD (‘One Document Does it all’) is a meta-language developed by the TEI, with which the formal description of a TEI or MEI schema can be created as well as its human-readable description in prose form, following the ‘Literate Programming’ approach. An ODD document itself is a regular TEI file (only extended by the tagdocs module) so that with a little experience in TEI, special schemas can be developed and customised for your own project relatively quickly.
+In this course, the concept of ODD as well as the underlying module and class systems of MEI and TEI will be introduced and then a first own schema will be created with the help of the Roma web editor. A further part will deal with the writing of the schema documentation (= electronic editorial guidelines), for which the ODD document will be further developed ‘by hand’.
+ +Programmierkenntnisse sowie das Verständnis zugrundeliegender Konzepte gewinnen in den Kultur- und Geisteswissenschaften zunehmend und fachübergreifend an Bedeutung. Die Programmiersprache Python erfreut sich großer Beliebtheit, da sie relativ zugänglich ist und viele nützliche Funktionen bietet, die das Arbeiten mit (Forschungs-)Daten ermöglichen und erleichtern. In diesem Kurs, der sich explizit an Anfänger*innen richtet, sollen zunächst allgemeine Grundlagen vermittelt werden, die dann das Erarbeiten einfacher Beispiele mit musikbezogenen Fragestellungen ermöglichen sollen.
+Der Social Evening ist ein geselliges Angebot zum informellen Austausch. + Wir gehen zusammen ins Le Feu, dort sind ab 19:00 Uhr einige Tische reserviert. Die Verpflegung erfolgt auf eigene Kosten. + Wir bitten um eine vorherige Anmeldung (wg. Reservierung).
+Der Kurs führt in die Theorie und Praxis der Textkodierung nach den Richtlinien der Text Encoding Initiative (TEI) ein. TEI wurde als XML-basierte Auszeichnungssprache gezielt für die Zwecke der Geisteswissenschaften konzipiert und ist seit vielen Jahren weltweit in wissenschaftlichen Editionsprojekten als das zentrale interoperable Standardformat für digitale Editionen etabliert.
+Nach einem knappen Blick auf die Prinzipien von XML-Sprachen führt der Kurs in die Grundlagen des TEI-Datenformats ein und gibt einen Überblick über die verschiedenen Module der TEI-Guidelines. Anhand verschiedener kurzer Kodierungsaufgaben werden diese Grundlagen schrittweise erweitert und individuell die Erstellung von TEI-Dateien eingeübt. Die Übungen werden jeweils gemeinsam besprochen. Wichtigstes Ziel des Kurses ist es, die Teilnehmer*innen zu einem selbständigen Umgang mit den TEI-Guidelines anzuleiten und damit für die Kodierungspraxis im Rahmen ihrer jeweiligen Projekte zu rüsten.
++ Die bereits 1998 vorgestellte eXtensible Markup Language (XML) spielt auch heute noch eine überaus große Rolle in der Datenrepräsentation und -verarbeitung. In den digital arbeitenden Geisteswissenschaften ist XML vor allem durch die Verwendung der etablierten Standards TEI und MEI als zentrales Datenformat etabliert. Doch auch weit über die Digital Humanities hinaus findet die Grundidee der semantischen Auszeichnung von Daten in verschiedensten Bereichen und in Form von unterschiedlichen auf XML basierenden Auszeichnungssprachen Anwendung: Auszeichnung von Texten, Repräsentation (und Auszeichnung) von Musik, Grafiken, Geodaten, mathematischen Formeln, zur Erfassung von Metadaten, zur Wissensrepräsentation, in der Serverkommunikation uvm.
+ +Für die Modellierung, Validierung, Transformation, Abfrage und Analyse von XML-basierten Daten stehen eine Reihe von X-Technologien (z.B. XML Schema, XSLT, XPath, XQuery) zur Verfügung. Diese werden im Kurs vorgestellt und in praktischen Übungen mit Hilfe des Oxygen XML Editors exemplarisch angewendet. Für die Übungen dürfen – zusätzlich zu den bereitgestellten Übungsdaten – gerne auch bereits vorhandene, eigene Daten mitgebracht werden.
+Entschuldigung! Leider ist bei der Registrierung etwas schiefgegangen. + Sollte der Fehler erneut auftreten, informieren Sie uns bitte mit einer + E-Mail an ess@edirom.de.
diff --git a/_archiv/2025/formTemplates/form_ok.html b/_archiv/2025/formTemplates/form_ok.html new file mode 100644 index 00000000..fc3b21e7 --- /dev/null +++ b/_archiv/2025/formTemplates/form_ok.html @@ -0,0 +1,6 @@ +--- +layout: post +title: Vielen Dank für Ihre Anmeldung +--- + +Sie erhalten in Kürze eine Bestätigung Ihrer Anmeldung per E-Mail.
diff --git a/_archiv/2025/formmail.php b/_archiv/2025/formmail.php new file mode 100644 index 00000000..48b5eea8 --- /dev/null +++ b/_archiv/2025/formmail.php @@ -0,0 +1,15416 @@ += 10 supports PHP 8. + * + * Copyright (c) 2001-2022 Open Concepts (Vic) Pty Ltd + * (ABN 12 130 429 248), Melbourne, Australia. + * This script is free for all use as described in the "Copying and Use" and + * "Warranty and Disclaimer" sections below. + * + * Visit us at http://www.tectite.com/ for updates and more information. + * + *** If you use Tectite FormMail, please support its development and other + *** freeware products by putting the following link on your website: + *** Visit www.tectite.com for free FormMail. + * + * Author: Russell Robinson + * First released: 2nd October 2001 + * + * Read This First + * ~~~~~~~~~~~~~~~ + * This script is very well documented and quite large! It looks daunting, + * but really isn't. + * If you have experience with PHP or other scripting languages, + * here's what you *need* to read: + * - Configuration (TARGET_EMAIL & DEF_ALERT) + * - Creating Forms + * That's it! (Alternatively, just read the Quick Start and/or + * Quicker Start section below). + * Full configuration documentation is here: + * http://www.tectite.com/fmdoc/index.php + * + * NOTE: do not read or modify this script or any PHP script + * with DreamWeaver or FrontPage! + * Many versions of those programs silently corrupt PHP scripts. + * + * Purpose: + * ~~~~~~~~ + * To accept information from an HTML form via HTTP and mail it to recipients. + * + * What does this PHP script do? + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * On your web site, you may have one or more HTML forms that accept + * information from people visiting your website. Your aim is for your + * website to email that information to you and/or add it to a database. + * FormMail performs those functions. + * + * Quick Start + * ~~~~~~~~~~~ + * 1. Edit this file and set TARGET_EMAIL for your requirements (near + * line 512 in this file - replace "yourhost\.com" with your mail server's + * name). We also strongly recommend you set DEF_ALERT (the next + * configuration below TARGET_EMAIL). + * 2. Install this file as formmail.php (or other name ending in .php) + * on your web server. + * Test alerts by using your browser to open a URL to the script: + * http://www.yourhost.com/formmail.php?testalert=1 + * Alerts are the only way FormMail can tell you the details of + * errors or faults. + * 3. Create an HTML form and: + * - specify a hidden field called "recipients" with the email address + * of the person to receive the form's results. + * - in the your form tag set the action attribute to + * the formmail.php you uploaded to your web server + * + * Once you have FormMail working, you may be interested in some advanced + * usage and features. We have HOW-TO guides at www.tectite.com which + * describe many of the advanced processing you can do with FormMail. + * http://www.tectite.com/fmhowto/guides.php + * + * Quicker Start + * ~~~~~~~~~~~~~ + * Use the FormMail Configuration Wizard here: + * http://www.tectite.com/wizards/fmconf.php + * By answering a few questions you'll get a configured FormMail and + * a sample HTML form ready to upload and use on your server. + * + * Features + * ~~~~~~~~ + * For a list of features go to: http://www.tectite.com/formmailpage.php + * + * Security + * ~~~~~~~~ + * Security is the primary concern in accepting data from your website + * visitors. + * Tectite FormMail has several security features designed into it. Note, + * however, it requires configuration for your particular web site. + * + * Configuration + * ~~~~~~~~~~~~~ + * To configure this script, go to the section titled "CONFIGURATION" + * (after reading the legal stuff below). + * + * There is only one mandatory setting: TARGET_EMAIL + * and one strongly recommended setting: DEF_ALERT + * + * Full configuration information is available here: + * http://www.tectite.com/fmdoc/index.php + * + * Creating Forms + * ~~~~~~~~~~~~~~ + * Go to this URL to learn how to write HTML forms for use with + * Tectite FormMail: http://www.tectite.com/fmdoc/creating_forms.php + * + * Copying and Use (Software License) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Tectite FormMail is provided free of charge and may be freely distributed + * and used provided that you: + * 1. keep this header, including copyright and comments, + * in place and unmodified; and, + * 2. do not charge a fee for distributing it, without an agreement + * in writing with Root Software allowing you to do so; and, + * 3. if you modify FormMail before distributing it, you clearly + * identify: + * a) who you are + * b) how to contact you + * c) what changes you have made + * d) why you have made those changes. + * + * By using any of our products, including this script, you are + * agreeing to our standard Terms and Conditions, available here: + * http://www.tectite.com/TermsAndConditions.pdf + * + * This is free software and the Software License shown above + * is to be read in conjunction with our standard Terms and Conditions. + * + * Warranty and Disclaimer + * ~~~~~~~~~~~~~~~~~~~~~~~ + * Tectite FormMail is provided free-of-charge and with ABSOLUTELY NO WARRANTY. + * It has not been verified for use in critical applications, including, + * but not limited to, medicine, defense, aircraft, space exploration, + * or any other potentially dangerous activity. + * + * By using Tectite FormMail you agree to indemnify Root Software and + * Open Concepts (Vic) Pty Ltd, their agents, employees, directors and + * associated companies and businesses from any liability whatsoever. + * + * We still care + * ~~~~~~~~~~~~~ + * If you find a bug or fault in FormMail, please report it to us. + * We will respond to your report and make endeavours to rectify any + * faults you've detected as soon as possible. + * + * To contact us view our contact information: + * http://www.tectite.com/contacts.php + * + * Version History + * ~~~~~~~~~~~~~~~ + * Near the top of this file, you'll find its version. The version + * line looks like this: + * $FM_VERS = "N.MM"; /* script version ... + * + * The version history used to be located within this file. However, + * starting with Version 8.00 we've moved it... + * + * You can read the complete version history of FormMail on our + * main website here: + * http://www.tectite.com/fmdoc/version_history.php + */ + +/** + * An alternative function for sending email. + * You can override this variable in a hook script to use a different function. + */ +$ALT_MAIL_FUNCTION = ''; + +FMDebug('Submission to: ' . (isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '') . ' from: ' . + (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); + +if (isset($_SERVER['REQUEST_METHOD']) && strtoupper($_SERVER['REQUEST_METHOD']) === 'OPTIONS') { + FMDebug('CORS OPTIONS request'); + CORS_Response(); + FormMailExit(); +} + +// +// Capture the current date and time, for various purposes. +// +date_default_timezone_set('UTC'); /* prevent notice in PHP 5.1+ */ +$lNow = time(); + +ini_set('track_errors',1); // enable $php_errormsg + +$aAlertInfo = array(); + +$sLangID = ""; // the language ID +$aMessages = array(); // all FormMail messages in the appropriate language + +function FormMailExit($s_mesg = '') +{ + if (($incFile = hookFileExists("fmhookonexit.inc")) !== false) { + @include($incFile); + } + exit($s_mesg); +} + +/** + * Interrogate and manage the execution environment. + * + * @package tectite_formmail + * @subpackage setup + */ +class ExecEnv +{ + /** + * Value of phpversion(). + * + * @var string + */ + private $_sPHPVersionString; + + /** + * Array containing the elements of the PHP version + * + * @var array + */ + private $_aPHPVersion; + + /** + * The URL for the script. + * + * @var string + */ + private $_sScript; + + /** + * Construct the class, and check PHP version. + */ + function __construct() + { + $this->_Init(); + $this->_CheckVersion(); + } + + /** + * Initialise the object. + * Sets {@link $_aPHPVersion} and {@link $_sPHPVersionString} + */ + private function _Init() + { + $this->_sPHPVersionString = phpversion(); + $this->_aPHPVersion = explode(".",$this->_ZapHyphenPart($this->_sPHPVersionString)); + } + + /** + * Remove any hyphenated component of a version string. + * + * @param $str + * + * @return false|string + */ + private function _ZapHyphenPart($str) + { + if (($i_pos = strpos($str,'-')) !== false) { + return substr($str,0,$i_pos); + } else { + return $str; + } + } + + /** + * @return array + */ + public function getPHPVersion() + { + return $this->_aPHPVersion; + } + + /** + * @return string + */ + public function getPHPVersionString() + { + return $this->_sPHPVersionString; + } + + /** + * Check for old version of PHP - die with a message if too old. + * + * This is actually not required because PHP 4 won't even accept + * the syntax of a PHP 5 script. However, we might need some + * other version check in the future, so this is a useful method + * to have around in that case. + */ + private function _CheckVersion() + { + $s_req_string = "5.0.0"; // We only support PHP 5 onward. + $a_too_old = explode(".",$s_req_string); + + $i_cannot_use = ($a_too_old[0] * 10000) + ($a_too_old[1] * 100) + $a_too_old[2]; + + $i_this_num = ($this->_aPHPVersion[0] * 10000) + ($this->_aPHPVersion[1] * 100) + + $this->_aPHPVersion[2]; + + if ($i_this_num <= $i_cannot_use) { + FormMailExit(GetMessage(MSG_SCRIPT_VERSION, + array("PHPREQ" => $s_req_string,"PHPVERS" => $this->_sPHPVersionString))); + } + } + + /** + * Test PHP version against a particular version string. + * + * @param $s_vers + * + * @return boolean true if the PHP version is at or later than the version + * specified + */ + public function IsPHPAtLeast($s_vers) + { + $a_test_version = explode(".",$s_vers); + if (count($a_test_version) < 3) { + return (false); + } + return ($this->_aPHPVersion[0] > $a_test_version[0] || ($this->_aPHPVersion[0] == + $a_test_version[0] && + ($this->_aPHPVersion[1] > + $a_test_version[1] || + $this->_aPHPVersion[1] == + $a_test_version[1] && + $this->_aPHPVersion[2] >= + $a_test_version[2]))); + } + + public function GetScript() + { + if (!isset($this->_sScript)) { + if (isset($_SERVER["PHP_SELF"]) && + !empty($_SERVER["PHP_SELF"]) && + isset($_SERVER["SERVER_NAME"]) && + !empty($_SERVER["SERVER_NAME"]) + ) { + if (isset($_SERVER["SERVER_PORT"]) && + $_SERVER["SERVER_PORT"] != 80 + ) { + if ($_SERVER["SERVER_PORT"] == 443) // SSL port + // + // just use https prefix + // + { + $this->_sScript = "https://" . $_SERVER["SERVER_NAME"] . + $_SERVER["PHP_SELF"]; + } else + // + // use http with port number + // + { + $this->_sScript = "http://" . $_SERVER["SERVER_NAME"] . + ":" . $_SERVER["SERVER_PORT"] . + $_SERVER["PHP_SELF"]; + } + } else { + $this->_sScript = "http://" . $_SERVER["SERVER_NAME"] . + $_SERVER["PHP_SELF"]; + } + } else { + Error("no_php_self",GetMessage(MSG_NO_PHP_SELF),false,false); + } + } + return ($this->_sScript); + } + + /** + * Get a boolean PHP setting. + * + * @param string $s_name the name of the setting + * + * @return bool|null the value of the setting + */ + public function getINIBool($s_name) + { + $m_val = ini_get($s_name); + if ($m_val !== null) { + if (is_numeric($m_val)) { + $m_val = (int)$m_val; + } elseif (is_string($m_val)) { + $m_val = strtolower($m_val); + switch ($m_val) { + case "1": + case "on": + case "true": + $m_val = true; + break; + default: + $m_val = false; + break; + } + } + } + return ($m_val); + } + + /** + * Return whether the session can be passed in a URL. + * + * @return bool true if the session can be passed in a URL + */ + public function allowSessionURL() + { + $m_only_cookies = $this->getINIBool('session.use_only_cookies'); + FMDebug('only_cookies=' . $m_only_cookies); + if ($m_only_cookies === null) { + $m_only_cookies = $this->IsPHPAtLeast('5.3.0'); + FMDebug('php=' . $this->IsPHPAtLeast('5.3.0') . ',only_cookies=' . $m_only_cookies); + } + return (!$m_only_cookies); + } + + public function getPostMaxSize() + { + $s_max_value = ini_get('post_max_size'); + $number = (int)substr($s_max_value,0,-1); + switch (strtoupper(substr($s_max_value,-1))) { + case "K": + return $number * 1024; + case "M": + return $number * pow(1024,2); + case "G": + return $number * pow(1024,3); + default: + return (int)$s_max_value; + } + } + + public function checkUploadSize() + { + if (isset($_SERVER['CONTENT_LENGTH'])) { + $n_size = (int)$_SERVER['CONTENT_LENGTH']; + $n_max = $this->getPostMaxSize(); + // echo "Size = $n_size, max = $n_max\n"; + if ($n_size > $n_max) { + UserError("post_size_limit",GetMessage(MSG_POST_SIZE_LIMIT,array(),false,false)); + } + } + } + + public function checkFileUploadSize($a_file_vars) + { + if (Settings::get('FILEUPLOADS')) { + $a_field_names = array_keys($a_file_vars); + foreach ($a_field_names as $s_name => $a_upload) { + if (isset($a_upload)) { + switch (isset($a_upload['error']) ? $a_upload['error'] : 0) { + case 0: // no error + case 4: // no file uploaded + break; + default: + UserError('file_upload_error',FieldManager::GetFileUploadErrorMesg($a_upload['error'])); + } + } + } + } + } +} + +$ExecEnv = new ExecEnv(); +if (!$ExecEnv->IsPHPAtLeast("5.3.0")) { + // + // disable this silly setting (usually not enabled) + // it's also deprecated from PHP version 5.3.0 + // + if (function_exists('set_magic_quotes_runtime')) { + /** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */ + @set_magic_quotes_runtime(0); + } +} + +// +// We set references to the appropriate arrays to handle PHP version differences +// Session vars are selected after we start the session. +// +$aServerVars = &$_SERVER; +$aGetVars = &$_GET; +$aFormVars = &$_POST; +$aFileVars = &$_FILES; +$aEnvVars = &$_ENV; + +$bIsGetMethod = false; +$bHasGetData = false; + +if (!isset($REAL_DOCUMENT_ROOT)) { + SetRealDocumentRoot(); +} + +if (isset($aServerVars['SERVER_PORT'])) { + $SCHEME = ($aServerVars['SERVER_PORT'] == 80) ? "http://" : "https://"; +} else { + $SCHEME = ""; +} +if (isset($aServerVars['SERVER_NAME']) && $aServerVars['SERVER_NAME'] !== "") { + $SERVER = $aServerVars['SERVER_NAME']; +} elseif (isset($aServerVars['SERVER_ADDR']) && $aServerVars['SERVER_ADDR'] !== "") { + $SERVER = $aServerVars['SERVER_ADDR']; +} else { + $SERVER = ""; +} + +/* + * Load an optional include file before the configuration. + * You can use this to set variables that can be used in the + * configuration section. + */ +if (includeFileExists("formmail-preconfig.inc.php")) { + @include("formmail-preconfig.inc.php"); +} + +/*****************************************************************************/ +/* CONFIGURATION (do not alter this line in any way!!!) */ +/***************************************************************************** + * This is the *only* place where you need to modify things to use formmail.php + * on your particular system. This section finishes at "END OF CONFIGURATION". + * Help for all settings can be found on our website: + * http://www.tectite.com/fmdoc/index.php + * + * Also, above each setting is a direct URL to the help information for the + * setting. + *****************************************************************************/ + +/* Help: http://www.tectite.com/fmdoc/email_name.php */ +$EMAIL_NAME = "^[-a-z0-9._]+"; /* the '^' is an important security feature! */ + +/* Help: http://www.tectite.com/fmdoc/target_email.php */ +$TARGET_EMAIL = array($EMAIL_NAME . "@edirom\.de$"); + +/* Help: http://www.tectite.com/fmdoc/email_addrs.php */ +$EMAIL_ADDRS = array(); + +/* Help: http://www.tectite.com/fmdoc/def_alert.php */ +$DEF_ALERT = "stadler@edirom.de"; + +/* Help: http://www.tectite.com/fmdoc/site_domain.php */ +$SITE_DOMAIN = ""; /* your website domain name */ + +/* Help: http://www.tectite.com/fmdoc/set_real_document_root.php */ +$SET_REAL_DOCUMENT_ROOT = ""; /* overrides the value set by SetRealDocumentRoot function */ + +// +// override $REAL_DOCUMENT_ROOT from the $SET_REAL_DOCUMENT_ROOT value (if any) +// Do not alter the following code (next 3 lines)! +// +if (isset($SET_REAL_DOCUMENT_ROOT) && $SET_REAL_DOCUMENT_ROOT !== "") { + $REAL_DOCUMENT_ROOT = $SET_REAL_DOCUMENT_ROOT; +} + +/* Help: http://www.tectite.com/fmdoc/config_check.php */ +$CONFIG_CHECK = array("TARGET_EMAIL"); + +/* Help: http://www.tectite.com/fmdoc/at_mangle.php */ +$AT_MANGLE = "be_ga"; + +/* Help: http://www.tectite.com/fmdoc/target_urls.php */ +$TARGET_URLS = array(); /* default; no URLs allowed */ + +/* Help: http://www.tectite.com/fmdoc/head_crlf.php */ +$HEAD_CRLF = "\r\n"; + +/* Help: http://www.tectite.com/fmdoc/body_lf.php */ +$BODY_LF = "\r\n"; /* the new default: use this for CR+LF */ +//$BODY_LF = "\n"; /* the old default: just LF */ + +/* Help: http://www.tectite.com/fmdoc/from_user.php */ +$FROM_USER = ""; /* the default - setting not used */ + +/* Help: http://www.tectite.com/fmdoc/sendmail_f_option.php */ +$SENDMAIL_F_OPTION = false; +$SENDMAIL_F_OPTION_LINE = __LINE__ - 1; /* don't modify this line! */ + +/* Help: http://www.tectite.com/fmdoc/fixed_sender.php */ +$FIXED_SENDER = ""; + +/* Help: http://www.tectite.com/fmdoc/set_sender_from_email.php */ +$SET_SENDER_FROM_EMAIL = false; + +/* Help: http://www.tectite.com/fmdoc/ini_set_from.php */ +$INI_SET_FROM = false; + +/* Help: http://www.tectite.com/fmdoc/logdir.php */ +$LOGDIR = ""; /* directory for log files; empty string to disallow log files */ + +/* Help: http://www.tectite.com/fmdoc/autorespondlog.php */ +$AUTORESPONDLOG = ""; /* file name in $LOGDIR for the auto responder log; empty string for no auto responder log */ + +/* Help: http://www.tectite.com/fmdoc/csv_file_settings.php */ +$CSVDIR = "/var/opt/ess"; /* directory for csv files; empty string to disallow csv files */ +$CSVSEP = ","; /* comma separator between fields (columns) */ +$CSVINTSEP = ";"; /* semicolon is the separator for fields (columns) with multiple values (checkboxes, etc.) */ +$CSVQUOTE = '"'; /* all fields in the CSV are quoted with this character; default is double quote. You can change it to single quote or leave it empty for no quotes. */ +//$CSVQUOTE = "'"; /* use this if you want single quotes */ +$CSVOPEN = ""; /* set to "b" to force line terminations to be kept as $CSVLINE setting below, regardless of operating + system. Keep as empty string and leave $CSVLINE unchanged, to get text file + terminations for your server's operating system. (Line feed on UNIX, carriage-return line feed on Windows). */ +$CSVLINE = "\n"; /* line termination for CSV files. The default is a single line feed, which may be modified for your + server's operating system. If you want to change + this value, you *must* set $CSVOPEN = "b". */ + +/* Help: http://www.tectite.com/fmdoc/templatedir.php */ +$TEMPLATEDIR = "/var/www/html/2024/formTemplates"; /* directory for template files; empty string if you don't have any templates */ + +/* Help: http://www.tectite.com/fmdoc/templateurl.php */ +$TEMPLATEURL = ""; /* default; no template URL */ + +/* Help: http://www.tectite.com/fmdoc/multiformdir.php */ +$MULTIFORMDIR = ""; /* directory for multi-form template files; empty string if you're not using multi-forms */ + +/* Help: http://www.tectite.com/fmdoc/multiformurl.php */ +$MULTIFORMURL = ""; /* default; no multi-forms templates URL */ + +/* Help: http://www.tectite.com/fmdoc/text_subs.php */ +$TEXT_SUBS = array( + array("srch" => "/\\\\r\\\\n/","repl" => "\r\n",), + array("srch" => "/\\\\n/","repl" => "\n",), + array("srch" => "/\\\\t/","repl" => "\t",), + array("srch" => "/\\[NL\\]/","repl" => "\n",), + array("srch" => "/\\[TAB\\]/","repl" => "\t",), + array("srch" => "/\\[NBSP\\]/","repl" => " ",), + array("srch" => "/\\[DQUOT\\]/","repl" => '"',), + array("srch" => "/\\[SQUOT\\]/","repl" => "'",), + array("srch" => "/\\[COLON\\]/","repl" => ":",), + array("srch" => "/\\[SLOSH\\]/","repl" => "\\",), + array("srch" => "/\\[OPCURL\\]/","repl" => "{",), + array("srch" => "/\\[CLCURL\\]/","repl" => "}",), + array("srch" => "/(on[a-z]*|href|src)\\s*=\\s*/i","repl" => ""), /* strip html attributes that could be unsafe */ + array("srch" => "/<\\s*(table|tr|td|th|p|ul|ol|li|b|i|u|strong|pre|h[1-6]|em|dl|dd|dt|hr|span|br)(\\b[^>]*?)>/i", + "repl" => "<\$1\$2>", + ), + array("srch" => "#<\\s*/\\s*(table|tr|td|th|p|ul|ol|li|b|i|u|strong|pre|h[1-6]|em|dl|dd|dt|hr|span|br)\\s*>#i", + "repl" => "\$1>", + ), +); + +/* Help: http://www.tectite.com/fmdoc/authentication_settings.php */ +$AUTHENTICATE = ""; +//$AUTHENTICATE = "Basic cnVzc2VsbHI6dGVzdA=="; // example +$AUTH_USER = ""; +$AUTH_PW = ""; + +/* Help: http://www.tectite.com/fmdoc/form_ini_file.php */ +$FORM_INI_FILE = ""; + +/* Help: http://www.tectite.com/fmdoc/moduledir.php */ +$MODULEDIR = "."; + +/* Help: http://www.tectite.com/fmdoc/fmcompute.php */ +$FMCOMPUTE = "fmcompute.php"; + +/* Help: http://www.tectite.com/fmdoc/fmgeoip.php */ +$FMGEOIP = "fmgeoip.php"; + +/* Help: http://www.tectite.com/fmdoc/advanced_templates.php */ +$ADVANCED_TEMPLATES = false; /* set to true for advanced templates */ + +/* Help: http://www.tectite.com/fmdoc/limited_import.php */ +$LIMITED_IMPORT = true; /* set to true if your database cannot handle escaped quotes or newlines within imported data. Microsoft Access is one example. */ + +/* Help: http://www.tectite.com/fmdoc/valid_env.php */ +$VALID_ENV = array('HTTP_REFERER','REMOTE_HOST','REMOTE_ADDR','REMOTE_USER', + 'HTTP_USER_AGENT' +); + +/* Help: http://www.tectite.com/fmdoc/fileuploads.php */ +$FILEUPLOADS = false; /* set to true to allow file attachments */ + +/* Help: http://www.tectite.com/fmdoc/max_file_upload_size.php */ +$MAX_FILE_UPLOAD_SIZE = 0; /* default of 0 means that other software */ +// controls the maximum file upload size +// (FormMail doesn't test the file size) + +/* Help: http://www.tectite.com/fmdoc/file_repository.php */ +$FILE_REPOSITORY = ""; + +/* Help: http://www.tectite.com/fmdoc/file_mode.php */ +$FILE_MODE = 0664; /* always precede with 0 to specify octal! */ + +/* Help: http://www.tectite.com/fmdoc/file_overwrite.php */ +$FILE_OVERWRITE = true; + +/* Help: http://www.tectite.com/fmdoc/next_num_file.php */ +$NEXT_NUM_FILE = ""; + +/* Help: http://www.tectite.com/fmdoc/put_data_in_url.php */ +$PUT_DATA_IN_URL = true; /* set to true to place data in the URL */ +// for bad_url redirects + +/* Help: http://www.tectite.com/fmdoc/allow_get_method.php */ +$ALLOW_GET_METHOD = false; + +/* Help: http://www.tectite.com/fmdoc/db_see_input.php */ +$DB_SEE_INPUT = false; /* set to true to just see the input values */ + +/* Help: http://www.tectite.com/fmdoc/db_see_ini.php */ +$DB_SEE_INI = false; /* set to true to just see the ini file */ + +/* Help: http://www.tectite.com/fmdoc/maxstring.php */ +$MAXSTRING = 4096; /* maximum string length for a value */ + +/* Help: http://www.tectite.com/fmdoc/require_captcha.php */ +$REQUIRE_CAPTCHA = "Confirm you are not a robot."; /* set to a message string if your forms */ +// must provide a CAPTCHA string + +/* Help: http://www.tectite.com/fmdoc/recaptcha_private_key.php */ +$RECAPTCHA_PRIVATE_KEY = ""; + +/* Help: http://www.tectite.com/fmdoc/bshowmesgnumbers.php */ +$bShowMesgNumbers = false; + +/* Help: http://www.tectite.com/fmdoc/filters.php */ +/* Note for Tectite personnel: the upgrade Wizard will merge new values + * but be careful of $var usage and quoting in new entries. + */ +/** @noinspection PhpUndefinedVariableInspection */ +$FILTERS = array("encode" => "$REAL_DOCUMENT_ROOT/cgi-bin/fmencoder -kpubkey.txt", + "null" => "null", + "csv" => "csv" +); + +/* Help: http://www.tectite.com/fmdoc/socket_filters.php */ +$SOCKET_FILTERS = array( + "httpencode" => array("site" => "YourSiteHere", + "port" => 80, + "path" => "/cgi-bin/fmencoder", + "params" => array(array("name" => "key", + "file" => "$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt" + ) + ) + ), + "sslencode" => array("site" => "ssl://YourSecureSiteHere", + "port" => 443, + "path" => "/cgi-bin/fmencoder", + "params" => array(array("name" => "key", + "file" => "$REAL_DOCUMENT_ROOT/cgi-bin/pubkey.txt" + ) + ) + ), +); + +/* Help: http://www.tectite.com/fmdoc/filter_attribs.php */ +$FILTER_ATTRIBS = array("encode" => "Strips,MIME=application/vnd.fmencoded,Encrypts", + "httpencode" => "Strips,MIME=application/vnd.fmencoded,Encrypts", + "sslencode" => "Strips,MIME=application/vnd.fmencoded,Encrypts", + "csv" => "Strips,MIME=text/csv", +); + +/* Help: http://www.tectite.com/fmdoc/check_for_new_version.php */ +$CHECK_FOR_NEW_VERSION = true; +$CHECK_DAYS = 30; + +/* Help: http://www.tectite.com/fmdoc/scratch_pad.php */ +$SCRATCH_PAD = ""; + +/* Help: http://www.tectite.com/fmdoc/cleanup_time.php */ +$CLEANUP_TIME = 60; /* cleanup time in minutes */ + +/* Help: http://www.tectite.com/fmdoc/cleanup_chance.php */ +$CLEANUP_CHANCE = 20; /* percentage probability that cleanup will be performed */ + +/* Help: http://www.tectite.com/fmdoc/pear_settings.php */ +$PEAR_SMTP_HOST = ""; +$PEAR_SMTP_PORT = 25; +$PEAR_SMTP_USER = ""; +$PEAR_SMTP_PWD = ""; + +/* Help: http://www.tectite.com/fmdoc/alert_on_user_error.php */ +$ALERT_ON_USER_ERROR = true; + +/* Help: http://www.tectite.com/fmdoc/enable_attack_detection.php */ +$ENABLE_ATTACK_DETECTION = true; + +/* Help: http://www.tectite.com/fmdoc/attack_detection_url.php */ +$ATTACK_DETECTION_URL = ""; + +/* Help: http://www.tectite.com/fmdoc/alert_on_attack_detection.php */ +$ALERT_ON_ATTACK_DETECTION = false; + +/* Help: http://www.tectite.com/fmdoc/attack_detection_mime.php */ +$ATTACK_DETECTION_MIME = true; + +/* Help: http://www.tectite.com/fmdoc/attack_detection_junk.php */ +$ATTACK_DETECTION_JUNK = false; +$ATTACK_DETECTION_JUNK_CONSONANTS = "bcdfghjklmnpqrstvwxz"; +$ATTACK_DETECTION_JUNK_VOWELS = "aeiouy"; +$ATTACK_DETECTION_JUNK_CONSEC_CONSONANTS = 5; +$ATTACK_DETECTION_JUNK_CONSEC_VOWELS = 4; +$ATTACK_DETECTION_JUNK_TRIGGER = 2; +$ATTACK_DETECTION_JUNK_LANG_STRIP = array( + "aiia", /* Hawaiian */ + "aeoa", /* palaeoanthropic */ + "aeoe", /* palaeoethnic */ + "ayou", /* layout */ + "ayee", /* payee */ + "buyout", /* buyout */ + "clayey", /* clayey */ + "hooey", /* hooey */ + "ioau", /* radioautograph */ + "opoeia", /* pharmacopoeia, onomatopoeia */ + "ooee", /* cooee */ + "oyee", /* employee */ + "ioau", /* radioautograph */ + "uaia", /* guaiac */ + "uaya", /* uruguayan */ + "ueou", /* aqueous */ + "uiou", /* obsequious */ + "uoya", /* buoyant */ + "queue", /* queue, queueing */ + "earth", /* earthquake, earthslide */ + "cks", /* jockstrap, backscratcher */ + "ngth", /* strengths, length */ + "ndths", /* thousandths */ + "ght", /* nightclub, knightsbridge */ + "phth", /* ophthalmology */ + "sch", /* rothschild */ + "shch", /* borshch */ + "scr", /* corkscrew */ + "spr", /* wingspread, offspring */ + "str", /* armstrong, songstress */ + "sts", /* bursts, postscript */ + "tch", /* catchphrase, scratchproof */ + "thst", /* northstar, birthstone */ + "http", /* https, http */ + "html", /* HTML, XHTML */ +); +$ATTACK_DETECTION_JUNK_IGNORE_FIELDS = array(); + +/* Help: http://www.tectite.com/fmdoc/attack_detection_dups.php */ +$ATTACK_DETECTION_DUPS = array("realname","address1","address2","country","zip", + "phone","postcode","state","email" +); + +/* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */ +$ATTACK_DETECTION_SPECIALS = true; + +/* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */ +$ATTACK_DETECTION_SPECIALS_ONLY_EMAIL = array("derive_fields","required", + "mail_options","good_url","bad_url","good_template", + "bad_template" +); + +/* Help: http://www.tectite.com/fmdoc/attack_detection_specials.php */ +$ATTACK_DETECTION_SPECIALS_ANY_EMAIL = array("subject"); + +/* Help: http://www.tectite.com/fmdoc/attack_detection_many_urls.php */ +$ATTACK_DETECTION_MANY_URLS = 0; + +/* Help: http://www.tectite.com/fmdoc/attack_detection_many_url_fields.php */ +$ATTACK_DETECTION_MANY_URL_FIELDS = 0; + +/* Help: http://www.tectite.com/fmdoc/attack_detection_url_patterns.php */ +$ATTACK_DETECTION_URL_PATTERNS = array( + '(^|[^-a-z_.0-9]+)(?'; + debug_print_backtrace(); + echo ''; + FormMailExit("No FormMail setting called '$s_name' exists."); + } + } + + /** + * Tests if the given config setting is empty. + * + * @param string $s_name the name of the config setting + * + * @return boolean true if the config setting is empty + */ + public static function isEmpty($s_name) + { + Settings::_check($s_name); + if (gettype($GLOBALS[$s_name]) == 'string') { + return ($GLOBALS[$s_name] === ''); + } else { + return (empty($GLOBALS[$s_name])); + } + } + + /** + * Returns the value of the given config setting. + * + * @param string $s_name the name of the config setting + * + * @return mixed the value of the config setting + */ + public static function get($s_name) + { + Settings::_check($s_name); + return ($GLOBALS[$s_name]); + } + + /** + * Set the value of a config setting. + * + * @param string $s_name the name of the config setting + * @param mixed $m_value the value to set for the config setting + */ + public static function set($s_name,$m_value) + { + Settings::_check($s_name); + if (($s_orig_type = gettype($GLOBALS[$s_name])) != ($s_new_type = gettype($m_value))) { + echo ''; + debug_print_backtrace(); + echo ''; + FormMailExit("You cannot set FormMail setting '$s_name' to type '$s_new_type'. It should be type '$s_orig_type'."); + } + $GLOBALS[$s_name] = $m_value; + } +} + +/* + * For PHP v8 we need to check each include file for existence first. + */ +function includeFileExists($file_name) +{ + return (stream_resolve_include_path($file_name) !== false); +} + +function hookFileExists($file_name) +{ + if (!Settings::isEmpty('HOOK_DIR')) { + $hook_file = Settings::get('HOOK_DIR') . DIRECTORY_SEPARATOR . $file_name . ".php"; + if (includeFileExists($hook_file)) { + return ($hook_file); + } + $hook_file = Settings::get('HOOK_DIR') . DIRECTORY_SEPARATOR . $file_name; + if (includeFileExists($hook_file)) { + return ($hook_file); + } + } + return (false); +} + +/* + * Load an optional include file after the configuration. + * You can use this to set variables or make adjustments + * based on the results of the configuration section. + */ +if (includeFileExists("formmail-preconfigdefs.inc.php")) { + @include("formmail-preconfigdefs.inc.php"); +} + +/* + * Many configuration settings used to be constants. However, constants + * cannot be re-defined in PHP. This limitation reduced the value + * of "formmail - postconfig . inc . php" and other hook scripts. + * Therefore, all configuration settings have been changed to be global + * variables (no define's). + * + * The following defines are for backward-compatibility with any existing + * hook scripts that are expecting the old constants. + */ +define("EMAIL_NAME",Settings::get("EMAIL_NAME")); +define("DEF_ALERT",Settings::get("DEF_ALERT")); +define("AT_MANGLE",Settings::get("AT_MANGLE")); +define("HEAD_CRLF",Settings::get("HEAD_CRLF")); +define("BODY_LF",Settings::get("BODY_LF")); +define("SENDMAIL_F_OPTION",Settings::get("SENDMAIL_F_OPTION")); +define("SENDMAIL_F_OPTION_LINE",Settings::get("SENDMAIL_F_OPTION_LINE")); +define("SET_SENDER_FROM_EMAIL",Settings::get("SET_SENDER_FROM_EMAIL")); +define("INI_SET_FROM",Settings::get("INI_SET_FROM")); +define("ADVANCED_TEMPLATES",Settings::get("ADVANCED_TEMPLATES")); +define("LIMITED_IMPORT",Settings::get("LIMITED_IMPORT")); +define("FILEUPLOADS",Settings::get("FILEUPLOADS")); +define("MAX_FILE_UPLOAD_SIZE",Settings::get("MAX_FILE_UPLOAD_SIZE")); +define("FILE_MODE",Settings::get("FILE_MODE")); +define("FILE_OVERWRITE",Settings::get("FILE_OVERWRITE")); +define("PUT_DATA_IN_URL",Settings::get("PUT_DATA_IN_URL")); +define("DB_SEE_INPUT",Settings::get("DB_SEE_INPUT")); +define("DB_SEE_INI",Settings::get("DB_SEE_INI")); +define("MAXSTRING",Settings::get("MAXSTRING")); +define("CHECK_FOR_NEW_VERSION",Settings::get("CHECK_FOR_NEW_VERSION")); +define("CHECK_DAYS",Settings::get("CHECK_DAYS")); +define("ALERT_ON_USER_ERROR",Settings::get("ALERT_ON_USER_ERROR")); +define("ENABLE_ATTACK_DETECTION",Settings::get("ENABLE_ATTACK_DETECTION")); +define("ATTACK_DETECTION_URL",Settings::get("ATTACK_DETECTION_URL")); +define("ALERT_ON_ATTACK_DETECTION",Settings::get("ALERT_ON_ATTACK_DETECTION")); +define("ATTACK_DETECTION_MIME",Settings::get("ATTACK_DETECTION_MIME")); +define("ATTACK_DETECTION_JUNK",Settings::get("ATTACK_DETECTION_JUNK")); +define("ATTACK_DETECTION_JUNK_CONSONANTS",Settings::get("ATTACK_DETECTION_JUNK_CONSONANTS")); +define("ATTACK_DETECTION_JUNK_VOWELS",Settings::get("ATTACK_DETECTION_JUNK_VOWELS")); +define("ATTACK_DETECTION_JUNK_CONSEC_CONSONANTS",Settings::get("ATTACK_DETECTION_JUNK_CONSEC_CONSONANTS")); +define("ATTACK_DETECTION_JUNK_CONSEC_VOWELS",Settings::get("ATTACK_DETECTION_JUNK_CONSEC_VOWELS")); +define("ATTACK_DETECTION_JUNK_TRIGGER",Settings::get("ATTACK_DETECTION_JUNK_TRIGGER")); +define("ATTACK_DETECTION_SPECIALS",Settings::get("ATTACK_DETECTION_SPECIALS")); +define("ATTACK_DETECTION_MANY_URLS",Settings::get("ATTACK_DETECTION_MANY_URLS")); +define("ATTACK_DETECTION_MANY_URL_FIELDS",Settings::get("ATTACK_DETECTION_MANY_URL_FIELDS")); +define("ATTACK_DETECTION_IGNORE_ERRORS",Settings::get("ATTACK_DETECTION_IGNORE_ERRORS")); +define("ZERO_IS_EMPTY",Settings::get("ZERO_IS_EMPTY")); +define("VALIDATE_EMAIL_DOMAIN",Settings::get("VALIDATE_EMAIL_DOMAIN")); +define("DESTROY_SESSION",Settings::get("DESTROY_SESSION")); + +// +// for Ajax allow GET method for cross site JSONP +// +if (IsAjax()) { + Settings::set('ALLOW_GET_METHOD',true); +} + +/* + * Load an optional include file after the configuration. + * You can use this to set variables or make adjustments + * based on the results of the configuration section. + */ +if (includeFileExists("formmail-postconfig.inc.php")) { + @include("formmail-postconfig.inc.php"); +} + +// @formatter:off + +// +// the following constants define all FormMail messages +// +// To re-align comments, use these search and replace patterns: +// Search Replace +// ^(\S{35,39})\s+// $1\t// +// ^(\S{31,35})\s+// $1\t\t// +// ^(\S{27,31})\s+// $1\t\t\t// +// ^(\S{23,27})\s+// $1\t\t\t\t// +// ^(\S{19,23})\s+// $1\t\t\t\t\t// +// +define('MSG_SCRIPT_VERSION',0); // This script requires at least PHP version... +define('MSG_END_VERS_CHK',1); // If you're happy... +define('MSG_VERS_CHK',2); // A later version of FormMail is available... +define('MSG_CHK_FILE_ERROR',3); // Unable to create check file... +define('MSG_UNK_VALUE_SPEC',4); // derive_fields: unknown value specification... +define('MSG_INV_VALUE_SPEC',5); // derive_fields: invalid value specification... +define('MSG_DERIVED_INVALID',6); // Some derive_fields specifications... +define('MSG_INT_FORM_ERROR',7); // Internal form error... +define('MSG_OPTIONS_INVALID',8); // Some mail_options settings... +define('MSG_PLSWAIT_REDIR',9); // Please wait while you are redirected... +define('MSG_IFNOT_REDIR',10); // If you are not redirected... +define('MSG_PEAR_OBJ',11); // Failed to create PEAR Mail object... +define('MSG_PEAR_ERROR',12); // PEAR Mail error... +define('MSG_NO_FOPT_ADDR',13); // You have specified "SendMailFOption"... +define('MSG_MORE_INFO',14); // More information... +define('MSG_INFO_STOPPED',15); // Extra alert information suppressed... +define('MSG_FM_ALERT',16); // FormMail alert +define('MSG_FM_ERROR',17); // FormMail script error +define('MSG_FM_ERROR_LINE',18); // The following error occurred... +define('MSG_USERDATA_STOPPED',19); // User data suppressed... +define('MSG_FILTERED',20); // This alert has been filtered... +define('MSG_TEMPLATES',21); // You must set either TEMPLATEDIR or TEMPLATEURL... +define('MSG_OPEN_TEMPLATE',22); // Failed to open template... +define('MSG_ERROR_PROC',23); // An error occurred while processing... +define('MSG_ALERT_DONE',24); // Our staff have been alerted... +define('MSG_PLS_CONTACT',25); // Please contact us directly... +define('MSG_APOLOGY',26); // We apologize for any inconvenience... +define('MSG_ABOUT_FORMMAIL',27); // Your form submission was processed by... +define('MSG_PREG_FAILED',28); // preg_match_all failed in FindCRMFields... +define('MSG_URL_INVALID',29); // CRM URL "$URL" is not valid... +define('MSG_URL_OPEN',30); // Failed to open Customer Relationship... +define('MSG_CRM_FAILED',31); // Failure report from CRM... +define('MSG_CRM_FORM_ERROR',32); // Your form submission was not... +define('MSG_OR',33); // "$ITEM1" or "$ITEM2" +define('MSG_NOT_BOTH',34); // not both "$ITEM1" and "$ITEM2" +define('MSG_XOR',35); // "$ITEM1" or "$ITEM2" (but not both) +define('MSG_IS_SAME_AS',36); // "$ITEM1" is the same as "$ITEM2" +define('MSG_IS_NOT_SAME_AS',37); // "$ITEM1" is not the same as "$ITEM2" +define('MSG_REQD_OPER',38); // Operator "$OPER" is not valid for "required" +define('MSG_PAT_FAILED',39); // Pattern operator "$OPER" failed: pattern... +define('MSG_COND_OPER',40); // Operator "$OPER" is not valid... +define('MSG_INV_COND',41); // Invalid "conditions" field... +define('MSG_COND_CHARS',42); // The conditions field "$FLD" is not valid... +define('MSG_COND_INVALID',43); // The conditions field "$FLD" is not valid... +define('MSG_COND_TEST_LONG',44); // Field "$FLD" has too many components... +define('MSG_COND_IF_SHORT',45); // Field "$FLD" has too few components for... +define('MSG_COND_IF_LONG',46); // Field "$FLD" has too many components for... +define('MSG_COND_UNK',47); // Field "$FLD" has an unknown command word... +define('MSG_MISSING',48); // Missing "$ITEM"... +define('MSG_NEED_ARRAY',49); // "$ITEM" must be an array... +define('MSG_SUBM_FAILED',50); // Your form submission has failed... +define('MSG_FILTER_WRONG',51); // Filter "$FILTER" is not properly... +define('MSG_FILTER_CONNECT',52); // Could not connect to site "$SITE"... +define('MSG_FILTER_PARAM',53); // Filter "$FILTER" has invalid parameter... +define('MSG_FILTER_OPEN_FILE',54); // Filter "$FILTER" cannot open file... +define('MSG_FILTER_FILE_ERROR',55); // Filter "$FILTER": read error on file... +define('MSG_FILTER_READ_ERROR',56); // Filter '$filter' failed: read error... +define('MSG_FILTER_NOT_OK',57); // Filter 'FILTER' failed... +define('MSG_FILTER_UNK',58); // Unknown filter... +define('MSG_FILTER_CHDIR',59); // Cannot chdir... +define('MSG_FILTER_NOTFOUND',60); // Cannot execute... +define('MSG_FILTER_ERROR',61); // Filter "$FILTER" failed... +define('MSG_SPARE',62); // this value is now spare +define('MSG_TEMPLATE_ERRORS',63); // Template "$NAME" caused the... +define('MSG_TEMPLATE_FAILED',64); // Failed to process template "$NAME"... +define('MSG_MIME_PREAMBLE',65); // (Your mail reader should not show this... +define('MSG_MIME_HTML',66); // This message has been generated by FormMail... +define('MSG_FILE_OPEN_ERROR',67); // Failed to open file "$NAME"... +define('MSG_ATTACH_DATA',68); // Internal error: AttachFile requires... +define('MSG_PHP_HTML_TEMPLATES',69); // HTMLTemplate option is only ... +define('MSG_PHP_FILE_UPLOADS',70); // For security reasons, file upload... +define('MSG_FILE_UPLOAD',71); // File upload attempt ignored... +define('MSG_FILE_UPLOAD_ATTACK',72); // Possible file upload attack... +define('MSG_PHP_PLAIN_TEMPLATES',73); // PlainTemplate option is only... +define('MSG_ATTACH_NAME',74); // filter_options: Attach must contain a name... +define('MSG_PHP_BCC',75); // Warning: BCC is probably not supported... +define('MSG_CSVCOLUMNS',76); // The "csvcolumns" setting is not... +define('MSG_CSVFILE',77); // The "csvfile" setting is not... +define('MSG_TARG_EMAIL_PAT_START',78); // Warning: Your TARGET_EMAIL pattern... +define('MSG_TARG_EMAIL_PAT_END',79); // Warning: Your TARGET_EMAIL pattern... +define('MSG_CONFIG_WARN',80); // The following potential problems... +define('MSG_PHP_AUTORESP',81); // Autorespond is only supported... +define('MSG_ALERT',82); // This is a test alert message... +define('MSG_NO_DEF_ALERT',83); // No DEF_ALERT value has been set.... +define('MSG_TEST_SENT',84); // Test message sent. Check your email..... +define('MSG_TEST_FAILED',85); // FAILED to send alert message... +define('MSG_NO_DATA_PAGE',86); // This URL is a Form submission program... +define('MSG_REQD_ERROR',87); // The form required some values that you... +define('MSG_COND_ERROR',88); // Some of the values you provided... +define('MSG_CRM_FAILURE',89); // The form submission did not succeed... +define('MSG_FOPTION_WARN',90); // Warning: You've used SendMailFOption in... +define('MSG_NO_ACTIONS',91); // The form has an internal error... +define('MSG_NO_RECIP',92); // The form has an internal error... +define('MSG_INV_EMAIL',93); // Invalid email addresses... +define('MSG_FAILED_SEND',94); // Failed to send email... +define('MSG_ARESP_EMAIL',96); // No "email" field was found. Autorespond... +define('MSG_ARESP_SUBJ',97); // Your form submission... +define('MSG_LOG_NO_VERIMG',98); // No VerifyImgString in session... +define('MSG_ARESP_NO_AUTH',99); // Failed to obtain authorization... +define('MSG_LOG_NO_MATCH',100); // User did not match image... +define('MSG_ARESP_NO_MATCH',101); // Your entry did not match... +define('MSG_LOG_FAILED',102); // Failed +define('MSG_ARESP_FAILED',103); // Autoresponder failed +define('MSG_LOG_OK',104); // OK +define('MSG_THANKS_PAGE',105); // Thanks! We've received your.... +define('MSG_LOAD_MODULE',106); // Cannot load module.... +define('MSG_LOAD_FMCOMPUTE',107); // Cannot load FMCompute.... +define('MSG_REGISTER_MODULE',108); // Cannot register module.... +define('MSG_COMP_PARSE',109); // These parse errors occurred.... +define('MSG_COMP_REG_DATA',110); // Failed to register data field.... +define('MSG_COMP_ALERT',111); // The following alert messages.... +define('MSG_COMP_DEBUG',112); // The following debug messages... +define('MSG_COMP_EXEC',113); // The following errors occurred.... +define('MSG_REG_FMCOMPUTE',114); // Cannot register function... +define('MSG_USER_ERRORS',115); // A number of errors occurred... +define('MSG_CALL_PARAM_COUNT',116); // Invalid parameter count... +define('MSG_CALL_UNK_FUNC',117); // Unknown function... +define('MSG_SAVE_FILE',118); // Failed to save file.... +define('MSG_CHMOD',119); // Failed to chmod file.... +define('MSG_VERIFY_MISSING',120); // Image verification string missing... +define('MSG_VERIFY_MATCH',121); // Your entry did not match... +define('MSG_FILE_NAMES_INVALID',122); // Some file_names specifications... +define('MSG_FILE_NAMES_NOT_FILE',123); // Your file_names specification... +define('MSG_TEMPL_ALERT',124); // The following alert messages.... +define('MSG_TEMPL_DEBUG',125); // The following debug messages... +define('MSG_TEMPL_PROC',126); // The following errors occurred.... +define('MSG_SAVE_FILE_EXISTS',127); // Cannot save file.... +define('MSG_EMPTY_ADDRESSES',128); // $COUNT empty addresses +define('MSG_CALL_INVALID_PARAM',129); // Invalid parameter.... +define('MSG_INI_PARSE_WARN',130); // Warning: your INI +define('MSG_INI_PARSE_ERROR',131); // The FormMail INI... +define('MSG_RECAPTCHA_MATCH',132); // reCaptcha verification failed... + +define('MSG_AND',133); // "$ITEM1" and "$ITEM2" +define('MSG_NEXT_PLUS_GOOD',134); // The form specifies both next_form and.... +define('MSG_MULTIFORM',135); // You must set either MULTIFORMDIR or MULTIFORMURL... +define('MSG_MULTIFORM_FAILED',136); // Failed to process multi-page form template "$NAME"... +define('MSG_NEED_THIS_FORM',137); // Multi-page forms require "this_form" field... +define('MSG_NO_PHP_SELF',138); // PHP on the server is not providing "PHP_SELF" +define('MSG_RETURN_URL_INVALID',139); // Return "$URL" is not valid... +define('MSG_GO_BACK',140); // Cannot 'go back' if not a multi-page form... +define('MSG_OPEN_URL',141); // Cannot open URL... +define('MSG_CANNOT_RETURN',142); // Cannot return to page.... +define('MSG_ATTACK_DETECTED',143); // Server attack detected.... +define('MSG_ATTACK_PAGE',144); // Your form submission.... +define('MSG_ATTACK_MIME_INFO',145); // The field "$FLD" contained... +define('MSG_ATTACK_DUP_INFO',146); // The fields "$FLD1" and... +define('MSG_ATTACK_SPEC_INFO',147); // Special field "$FLD"... +define('MSG_NEED_SCRATCH_PAD',148); // You need to set SCRATCH_PAD... +define('MSG_MULTI_UPLOAD',149); // File upload processing failed during multi-page form processing. +define('MSG_OPEN_SCRATCH_PAD',150); // Cannot open directory... +define('MSG_NO_NEXT_NUM_FILE',151); // You cannot use the %nextnum% feature... +define('MSG_NEXT_NUM_FILE',152); // Cannot process next number... +define('MSG_ATTACK_MANYURL_INFO',153); // Field "$FLD"... +define('MSG_ATTACK_MANYFIELDS_INFO',154); // $NUM fields have URLs.... +define('MSG_REV_CAP',155); // ATTACK_DETECTION_REVERSE_CAPTCHA setting.... +define('MSG_ATTACK_REV_CAP_INFO',156); // The field "$FLD" contained... +define('MSG_ATTACK_JUNK_INFO',157); // The field "$FLD" contained... +define('MSG_ARESP_EMPTY',158); // The autoresponse... +define('MSG_LOG_RECAPTCHA',159); // reCaptcha process failed... + +define('MSG_URL_PARSE',160); // URL parse failed +define('MSG_URL_SCHEME',161); // Unsupported URL scheme... +define('MSG_SOCKET',162); // Socket error ... +define('MSG_GETURL_OPEN',163); // Open URL failed: ... +define('MSG_RESOLVE',164); // Cannot resolve... + +define('MSG_FORM_OK',170); // Form Submission Succeeded +define('MSG_FORM_ERROR',171); // Form Submission Error +define('MSG_GET_DISALLOWED',172); // GET method has... +define('MSG_INVALID_SENDER',173); // The form has specified an invalid sender +define('MSG_SET_SENDER_FROM_EMAIL',174); // SET_SENDER_FROM_EMAIL is no longer supported +// +// The following are PHP's file upload error messages +// +define('MSG_FILE_UPLOAD_ERR_UNK',180); // Unknown error code. +define('MSG_FILE_UPLOAD_ERR1',181); // The uploaded file exceeds the upload_max_filesize directive in php.ini. +define('MSG_FILE_UPLOAD_ERR2',182); // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form. +define('MSG_FILE_UPLOAD_ERR3',183); // The uploaded file was only partially uploaded. +define('MSG_FILE_UPLOAD_ERR4',184); // No file was uploaded. +define('MSG_FILE_UPLOAD_ERR6',186); // Missing a temporary folder. +define('MSG_FILE_UPLOAD_ERR7',187); // Failed to write file to disk. +define('MSG_FILE_UPLOAD_ERR8',188); // File upload stopped by extension. +define('MSG_FILE_UPLOAD_SIZE',189); // Uploaded file "$NAME" is too big... (not a PHP error code - internal maximum file size error) +define('MSG_POST_SIZE_LIMIT',190); // Your form submission exceeds the server's configured size limit. +// +// following are for derive_fields functions +// +define('MSG_DER_FUNC_ERROR',200); // derive_fields: invalid function.... +define('MSG_DER_FUNC_SIZE_FMT',201); // function 'size' requires.... +define('MSG_DER_FUNC_IF_FMT',202); // function 'if' requires.... +define('MSG_DER_FUNC_NEXTNUM_FMT',203); // function 'nextnum' requires.... +define('MSG_DER_FUNC_EXT_FMT',204); // function 'ext' requires.... +define('MSG_DER_FUNC1_FMT',205); // function 'FUNC' requires.... +define('MSG_DER_FUNC_SUBSTR_FMT',206); // function 'substr' requires.... + +define('MSG_USER_ATTACK_JUNK',220); // The following input ... +define('MSG_USER_ATTACK_REV_CAP',221); // Your input ... +define('MSG_USER_ATTACK_DUP',222); // You have ... +define('MSG_USER_ATTACK_MANY_URLS',223); // Your input ... +define('MSG_USER_ATTACK_MANY_URL_FIELDS',224); // Your input ... + +define('MSG_INVALID_EMAIL',230); // The email address...is invalid + +// +// The following messages are no longer used +// +define('MSG_FLD_NOTFOUND', 900); + + +// @formatter:on +// Jump to: + +// +// Return true if using the built-in language +// +/** @noinspection PhpUnused */ +function IsBuiltInLanguage() +{ + global $sLangID; + + return (strpos($sLangID,"builtin") !== false); +} + +$sSavePath = ""; +$bPathSaved = false; +// +// Set include path to include the given directory. +// +function AddIncludePath($s_dir = ".") +{ + global $sSavePath,$bPathSaved; + + $s_path = ini_get('include_path'); + $i_path_len = strlen($s_path); + $s_sep = IsServerWindows() ? ";" : ":"; // get path separator + // + // look for it in the include_path + // + $b_found = false; + $i_pos = 0; + $i_len = strlen($s_dir); + while (!$b_found && ($i_pos = strpos($s_path,$s_dir,$i_pos)) !== false) { + if ($i_pos == 0) { + if ($i_len == $i_path_len) { + $b_found = true; + } // the path only has $s_dir + elseif ($s_path[$i_len] == $s_sep) { + $b_found = true; + } + } elseif ($s_path[$i_pos - 1] == $s_sep && + ($i_pos + $i_len == $i_path_len || + $s_path[$i_pos + $i_len] == $s_sep) + ) { + $b_found = true; + } + if (!$b_found) { + $i_pos++; + } + } + if (!$b_found) { + // + // allow multiple calls, but only store the original path once + // + if (!$bPathSaved) { + $sSavePath = $s_path; + } + if (empty($s_path)) { + $s_path = $s_dir; + } else + // + // prepend the directory + // + { + $s_path = $s_dir . $s_sep . $s_path; + } + ini_set('include_path',$s_path); + $bPathSaved = true; + } +} + +// +// Reset the include path after a call to AddIncludePath. +// +function ResetIncludePath() +{ + global $sSavePath,$bPathSaved; + + if ($bPathSaved) { + ini_set('include_path',$sSavePath); + $bPathSaved = false; + } +} + +// +// Load a language file +// +function LoadLanguageFile() +{ + global $aMessages,$sLangID,$sHTMLCharSet; + + AddIncludePath(); + if (includeFileExists("language.inc.php")) { + include("language.inc.php"); + } else { + if (includeFileExists("language.inc")) { + include("language.inc"); + } + } + + ResetIncludePath(); + if (isset($sHTMLCharSet) && $sHTMLCharSet !== "") { + header("Content-Type: text/html; charset=$sHTMLCharSet"); + } +} + +// +// Load the messages array from the default language, and then +// override with an optional language file. +// Note: all messages get the MNUM parameter sent which they can use. +// If they don't use it, the message number is appended. +// +function LoadBuiltinLanguage() +{ + global $aMessages,$sLangID; + + $sLangID = "English (builtin)"; + // MSG_SCRIPT_VERSION is shown if the PHP version is too old to run + // FormMail + // Parameters: + // $PHPREQ is the minimum required PHP version + // $PHPVERS is the version the server currently has installed. + $aMessages[MSG_SCRIPT_VERSION] = 'This script requires at least PHP version ' . + '$PHPREQ. You have PHP version $PHPVERS.'; + + // MSG_END_VERS_CHK is sent at the end of an Alert message when + // FormMail detects that there's a newer version available + // Parameters: none + $aMessages[MSG_END_VERS_CHK] = '***************************************************\n' . + 'If you are happy with your current version and want\n' . + 'to stop these reminders, edit formmail.php and\n' . + 'set CHECK_FOR_NEW_VERSION to false.\n' . + '***************************************************\n'; + + // MSG_VERS_CHK is sent in an Alert message when + // FormMail detects that there's a newer version available + // Parameters: + // $TECTITE the website to go to + // $FM_VERS the current FormMail version + // $NEWVERS the new FormMail version that's available + $aMessages[MSG_VERS_CHK] = 'A later version of FormMail is available from $TECTITE.\n' . + 'You are currently using version $FM_VERS.\n' . + 'The new version available is $NEWVERS.\n'; + + // MSG_CHK_FILE_ERROR is sent in an Alert message when + // FormMail cannot create a file to record the time of version check. + // Parameters: + // $FILE the file name that could not be created + // $ERROR the actual error message + $aMessages[MSG_CHK_FILE_ERROR] = 'Unable to create check file "$FILE": $ERROR'; + + // MSG_UNK_VALUE_SPEC is sent in an Alert message when + // a form uses an unknown value specification in derive_fields. + // Parameters: + // $SPEC the unknown value specification + // $MSG additional message + $aMessages[MSG_UNK_VALUE_SPEC] = 'derive_fields: unknown value specification ' . + '"$SPEC"$MSG'; + + // MSG_INV_VALUE_SPEC is sent in an Alert message when + // a form uses a value specification in derive_fields that's + // formatted incorrectly (missing terminating '%') + // Parameters: + // $SPEC the invalid value specification + $aMessages[MSG_INV_VALUE_SPEC] = 'derive_fields: invalid value specification ' . + '"$SPEC" (possibly missing a "%")'; + + // MSG_DERIVED_INVALID is sent in an Alert message when + // a form's derive_fields setting has errors + // Parameters: none + // A list of errors is appended on separate lines + $aMessages[MSG_DERIVED_INVALID] = 'Some derive_fields specifications are invalid $MNUM:\n'; + + // MSG_INT_FORM_ERROR is sent in an Alert message and displayed + // to the form user + // Parameters: none + $aMessages[MSG_INT_FORM_ERROR] = 'Internal form error'; + + // MSG_OPTIONS_INVALID is sent in an Alert message when + // a form's options settings are invalid. This applies to + // mail_options, filter_options, crm_options, and autorespond + // Parameters: + // $OPT the name of the options field + // A list of errors is appended on separate lines + $aMessages[MSG_OPTIONS_INVALID] = 'Some $OPT settings are undefined $MNUM:\n'; + + // MSG_PLSWAIT_REDIR is shown to the user for a redirect + // with JavaScript + // Parameters: none + $aMessages[MSG_PLSWAIT_REDIR] = 'Please wait while you are redirected...'; + + // MSG_IFNOT_REDIR is shown to the user for a redirect + // with JavaScript + // Parameters: + // $URL the URL to redirect to + $aMessages[MSG_IFNOT_REDIR] = 'If you are not automatically redirected, ' . + 'please click here.'; + + // MSG_PEAR_OBJ is shown to the user if the PEAR Mail object + // cannot be created + // Parameters: none + $aMessages[MSG_PEAR_OBJ] = 'Failed to create PEAR Mail object'; + + // MSG_PEAR_ERROR is sent in an Alert message if the PEAR Mail processing + // reports an error + // Parameters: + // $MSG the error message from PEAR + $aMessages[MSG_PEAR_ERROR] = 'PEAR Mail error: $MSG'; + + // MSG_NO_FOPT_ADDR is sent in an Alert message SendMailFOption is + // specified in the form and no email address has been provided + // Parameters: none + $aMessages[MSG_NO_FOPT_ADDR] = 'You have specified "SendMailFOption" in your ' . + 'form, but there is no email address to use'; + + // MSG_MORE_INFO is sent in an Alert message on a line by itself, just + // before extra information about the FormMail processing that may have + // led to the alert message + // Parameters: none + $aMessages[MSG_MORE_INFO] = 'More information:'; + + // MSG_INFO_STOPPED is sent in an Alert message to say that extra + // alert information has been suppressed because of potential security + // problems with showing it. + // Parameters: none + $aMessages[MSG_INFO_STOPPED] = '(Extra alert information suppressed for ' . + 'security purposes. $MNUM)'; + + // MSG_FM_ALERT is sent as the subject line of an Alert message + // Parameters: none + $aMessages[MSG_FM_ALERT] = 'FormMail alert'; + + // MSG_FM_ERROR is sent as the subject line of an Alert message + // Parameters: none + $aMessages[MSG_FM_ERROR] = 'FormMail script error'; + + // MSG_FM_ERROR_LINE is sent in an Alert message on a + // separate line to introduce the actual error message + // Parameters: none + $aMessages[MSG_FM_ERROR_LINE] = 'The following error occurred in FormMail $MNUM:'; + + // MSG_USERDATA_STOPPED is sent in an Alert message to say that the + // user's data has been suppressed because of potential security + // problems with showing it. + // Parameters: none + $aMessages[MSG_USERDATA_STOPPED] = '(User data suppressed for security ' . + 'purposes. $MNUM)'; + + // MSG_FILTERED is sent in an Alert message to show what filter + // has been used on the message + // Parameters: + // $FILTER the name of the filter + $aMessages[MSG_FILTERED] = 'This alert has been filtered through "$FILTER" ' . + 'for security purposes.'; + + // MSG_TEMPLATES is sent in an Alert message when a form tries + // to use a template, but templates have not been configured in + // formmail.php + // Parameters: none + $aMessages[MSG_TEMPLATES] = 'You must set either TEMPLATEDIR or TEMPLATEURL ' . + 'in formmail.php before you can specify ' . + 'templates in your forms.'; + + // MSG_OPEN_TEMPLATE is sent in an Alert message when FormMail cannot + // open a template file + // Parameters: + // $NAME the name of the template file + // $ERROR information about the error + $aMessages[MSG_OPEN_TEMPLATE] = 'Failed to open template "$NAME" $MNUM: $ERROR'; + + // MSG_ERROR_PROC is shown to the user as part of an error + // page. This message introduces the error. + // Parameters: none + $aMessages[MSG_ERROR_PROC] = 'An error occurred while processing the ' . + 'form $MNUM.\n\n'; + + // MSG_ALERT_DONE is shown to the user as part of an error + // page if an Alert message has been sent to the website owner. + // Parameters: + // SERVER the name of the server (website) + $aMessages[MSG_ALERT_DONE] = 'The staff at $SERVER have been alerted to the error $MNUM.\n'; + + // MSG_PLS_CONTACT is shown to the user as part of an error + // page if an Alert message could *not* be sent to the website owner. + // Parameters: + // SERVER the name of the server (website) + $aMessages[MSG_PLS_CONTACT] = 'Please contact us ($SERVER) directly since this form ' . + 'is not working $MNUM.\n'; + + // MSG_APOLOGY is shown to the user as part of an error + // page as an apology for a problem with the form. + // Parameters: + // SERVER the name of the server (website) + $aMessages[MSG_APOLOGY] = '$SERVER apologizes for any inconvenience this error ' . + 'may have caused.'; + + // MSG_ABOUT_FORMMAIL is shown to the user at the foot of pages + // generated by FormMail (e.g. the default "Thanks" page and default + // error page). + // Parameters: + // $FM_VERS the FormMail version number + // $TECTITE www.tectite.com + $aMessages[MSG_ABOUT_FORMMAIL] = 'Your form submission was processed by ' . + 'FormMail ' . + '($FM_VERS), a PHP script available from ' . + '$TECTITE.'; + + // MSG_PREG_FAILED is sent in an Alert message if the TectiteCRM + // system failed to return the expected result. + // Parameters: none + $aMessages[MSG_PREG_FAILED] = 'preg_match_all failed in FindCRMFields'; + + // MSG_URL_INVALID is sent in an Alert message if the specified + // URL for TectiteCRM is not valid according to the TARGET_URLS + // configuration setting + // Parameters: + // $URL the invalid URL + $aMessages[MSG_URL_INVALID] = 'The URL "$URL" to access the Customer ' . + 'Relationship Management System is not valid ' . + '(see TARGET_URLS in formmail.php)'; + + // MSG_URL_OPEN is sent in an Alert message if the specified + // URL for TectiteCRM cannot be opened + // Parameters: + // $URL the invalid URL + // $ERROR information about the error + $aMessages[MSG_URL_OPEN] = 'Failed to open Customer Relationship ' . + 'Management System URL "$URL" $MNUM: $ERROR'; + + // MSG_CRM_FAILED is sent in an Alert message if the TectiteCRM + // system doesn't return an OK message + // Parameters: + // $URL the invalid URL + // $MSG more information + $aMessages[MSG_CRM_FAILED] = 'Failure report from Customer Relationship ' . + 'Management System (url="$URL") $MNUM: $MSG'; + + // MSG_CRM_FORM_ERROR is shown to the user if the information + // passed to TectiteCRM was not accepted + // Parameters: none + $aMessages[MSG_CRM_FORM_ERROR] = 'Your form submission was not accepted'; + + // MSG_AND is shown to the user; it shows two items separated + // by "and" + // Parameters: + // $ITEM1 the first item + // $ITEM2 the second item + $aMessages[MSG_AND] = '"$ITEM1" and "$ITEM2"'; + + // MSG_OR is shown to the user; it shows two items separated + // by "or" + // Parameters: + // $ITEM1 the first item + // $ITEM2 the second item + $aMessages[MSG_OR] = '"$ITEM1" or "$ITEM2"'; + + // MSG_NOT_BOTH is shown to the user; it shows two items that must + // be specified together + // Parameters: + // $ITEM1 the first item + // $ITEM2 the second item + $aMessages[MSG_NOT_BOTH] = 'not both "$ITEM1" and "$ITEM2"'; + + // MSG_XOR is shown to the user; it shows two items that must + // not be specified together + // Parameters: + // $ITEM1 the first item + // $ITEM2 the second item + $aMessages[MSG_XOR] = '"$ITEM1" or "$ITEM2" (but not both)'; + + // MSG_IS_SAME_AS is shown to the user; it shows two items that must + // not be the same value + // Parameters: + // $ITEM1 the first item + // $ITEM2 the second item + $aMessages[MSG_IS_SAME_AS] = '"$ITEM1" is the same as "$ITEM2"'; + + // MSG_IS_NOT_SAME_AS is shown to the user; it shows two items that must + // be the same value + // Parameters: + // $ITEM1 the first item + // $ITEM2 the second item + $aMessages[MSG_IS_NOT_SAME_AS] = '"$ITEM1" is not the same as "$ITEM2"'; + + // MSG_REQD_OPER is sent in an Alert message when an unknown + // operator has been used in a "required" specification + // Parameters: + // $OPER the unknown operator + $aMessages[MSG_REQD_OPER] = 'Operator "$OPER" is not valid for "required"'; + + // MSG_PAT_FAILED is sent in an Alert message when a "conditions" pattern + // match has not matched anything (this isn't necessarily an error) + // Parameters: + // $OPER the "conditions" operator + // $PAT the "conditions" pattern + // $VALUE the value that was searched + $aMessages[MSG_PAT_FAILED] = 'Pattern operator "$OPER" failed: pattern ' . + '"$PAT", value searched was "$VALUE".'; + + // MSG_COND_OPER is sent in an Alert message when a "conditions" + // operator is not value + // Parameters: + // $OPER the "conditions" operator + $aMessages[MSG_COND_OPER] = 'Operator "$OPER" is not valid for "conditions"'; + + // MSG_INV_COND is sent in an Alert message when a "conditions" + // field is not valid + // Parameters: + // FLD the field name + $aMessages[MSG_INV_COND] = 'Invalid "conditions" field "$FLD" - not a string or array.'; + + // MSG_COND_CHARS is sent in an Alert message when a "conditions" + // field is missing the mandatory first 2 characters (the separators) + // Parameters: + // FLD the field name + // COND the conditions field value + $aMessages[MSG_COND_CHARS] = 'The conditions field "$FLD" is not valid. ' . + 'You must provide the two separator ' . + 'characters at the beginning. You had "$COND".'; + + // MSG_COND_INVALID is sent in an Alert message when a "conditions" + // field has the wrong format + // Parameters: + // FLD the field name + // COND the conditions field value + // SEP the internal separator character for the field. + $aMessages[MSG_COND_INVALID] = 'The conditions field "$FLD" is not valid. ' . + 'There must be at least 5 components ' . + 'separated by "$SEP". Your value was "$COND".'; + + // MSG_COND_TEST_LONG is sent in an Alert message when a "conditions" + // TEST value has too many components + // Parameters: + // FLD the field name + // COND the conditions field value + // SEP the list separator character for the field. + $aMessages[MSG_COND_TEST_LONG] = 'Field "$FLD" has too many components for ' . + 'a "TEST" command: "$COND".\nAre you missing ' . + 'a "$SEP"?'; + + // MSG_COND_IF_SHORT is sent in an Alert message when a "conditions" + // IF value has too few components + // Parameters: + // FLD the field name + // COND the conditions field value + // SEP the internal separator character for the field. + $aMessages[MSG_COND_IF_SHORT] = 'Field "$FLD" has too few components for ' . + 'an "IF" command: "$COND".\nThere must be ' . + 'at least 6 components separated by "$SEP"'; + + // MSG_COND_IF_LONG is sent in an Alert message when a "conditions" + // IF value has too many components + // Parameters: + // FLD the field name + // COND the conditions field value + // SEP the list separator character for the field. + $aMessages[MSG_COND_IF_LONG] = 'Field "$FLD" has too many components for ' . + 'an "IF" command: "$COND".\nAre you missing ' . + 'a "$SEP"?'; + + // MSG_COND_UNK is sent in an Alert message when a "conditions" + // value has an unknown command + // Parameters: + // FLD the field name + // COND the conditions field value + // CMD the unknown command + $aMessages[MSG_COND_UNK] = 'Field "$FLD" has an unknown command word ' . + '"$CMD": "$COND".'; + + // MSG_MISSING is sent in an Alert message when + // a socket filter is incorrectly defined + // Parameters: + // ITEM the missing item + $aMessages[MSG_MISSING] = 'Missing "$ITEM"'; + + // MSG_NEED_ARRAY is sent in an Alert message when + // a socket filter is incorrectly defined + // Parameters: + // ITEM the item that should be an array + $aMessages[MSG_NEED_ARRAY] = '"$ITEM" must be an array'; + + // MSG_SUBM_FAILED is shown to the user when an internal error + // as occurred and that error is not to be shown + // Parameters: none + $aMessages[MSG_SUBM_FAILED] = 'Your form submission has failed due to ' . + 'an error on our server.'; + + // MSG_FILTER_WRONG is sent in an Alert message when + // a socket filter is incorrectly defined + // Parameters: + // FILTER the filter name + // ERRORS a string containing a list of errors + $aMessages[MSG_FILTER_WRONG] = 'Filter "$FILTER" is not properly defined: ' . + '$ERRORS'; + + // MSG_FILTER_CONNECT is sent in an Alert message when FormMail + // cannot connect to a socket filter + // Parameters: + // FILTER the filter name + // SITE the site + // ERRNUM socket error number + // ERRSTR socket error message + $aMessages[MSG_FILTER_CONNECT] = 'Could not connect to site "$SITE" ' . + 'for filter "$FILTER" ($ERRNUM): $ERRSTR'; + + // MSG_FILTER_PARAM is sent in an Alert message when a socket + // filter has an invalid parameter specification + // Parameters: + // FILTER the filter name + // NUM parameter number + // NAME parameter name + $aMessages[MSG_FILTER_PARAM] = 'Filter "$FILTER" has invalid parameter ' . + '#$NUM: no "$NAME"'; + + // MSG_FILTER_OPEN_FILE is sent in an Alert message when a socket + // filter cannot open the required file + // Parameters: + // FILTER the filter name + // FILE the file that could not be opened + // ERROR the error message + $aMessages[MSG_FILTER_OPEN_FILE] = 'Filter "$FILTER" cannot open file ' . + '"$FILE": $ERROR'; + + // MSG_FILTER_FILE_ERROR is sent in an Alert message when a socket + // filter gets an error message during reading a file + // Parameters: + // FILTER the filter name + // FILE the file that could not be opened + // ERROR the error message + // NLINES the number of lines that were read successfully + $aMessages[MSG_FILTER_FILE_ERROR] = 'Filter "$FILTER": read error on file ' . + '"$FILE" after $NLINES lines: $ERROR'; + + // MSG_FILTER_READ_ERROR is sent in an Alert message when a socket + // filter gets an error during reading from the socket + // Parameters: + // FILTER the filter name + // ERROR the error message + $aMessages[MSG_FILTER_READ_ERROR] = 'Filter "$FILTER" failed: read error: ' . + '$ERROR'; + + // MSG_FILTER_NOT_OK is sent in an Alert message when a socket + // filter fails to return the agreed __OK__ indicator + // Parameters: + // FILTER the filter name + // DATA the data returned from the filter + $aMessages[MSG_FILTER_NOT_OK] = 'Filter "$FILTER" failed (missing ' . + '__OK__ line): $DATA'; + + // MSG_FILTER_UNK is sent in an Alert message + // when an unknown filter is specified by a form + // Parameters: + // FILTER the filter name + $aMessages[MSG_FILTER_UNK] = 'Unknown filter "$FILTER"'; + + // MSG_FILTER_CHDIR is sent in an Alert message + // when FormMail cannot change to the filter's directory + // Parameters: + // FILTER the filter name + // DIR the directory name + // ERROR an error message from the system + $aMessages[MSG_FILTER_CHDIR] = 'Cannot chdir to "$DIR" to run filter ' . + '"$FILTER": $ERROR'; + + // MSG_FILTER_NOTFOUND is sent in an Alert message + // when FormMail cannot execute the filter + // Parameters: + // FILTER the filter name + // CMD the command line being executed + // ERROR an error message from the system + $aMessages[MSG_FILTER_NOTFOUND] = 'Cannot execute filter "$FILTER" with ' . + 'command "$CMD": $ERROR'; + + // MSG_FILTER_ERROR is sent in an Alert message + // when a filter returns a non-zero status + // Parameters: + // FILTER the filter name + // ERROR an error message from the system + // STATUS the status return from the command + $aMessages[MSG_FILTER_ERROR] = 'Filter "$FILTER" failed (status $STATUS): ' . + '$ERROR'; + + // MSG_SPARE is a spare message + $aMessages[MSG_SPARE] = ''; + + // MSG_TEMPLATE_ERRORS is sent as part of an Alert message + // when a template has generated some errors. The message + // should end with a new line and the actual errors are + // output after it. + // Parameters: + // NAME the template name + $aMessages[MSG_TEMPLATE_ERRORS] = 'Template "$NAME" caused the ' . + 'following errors $MNUM:\n'; + + // MSG_TEMPLATE_FAILED is sent in an Alert message + // when processing a template has failed. + // Parameters: + // NAME the template name + $aMessages[MSG_TEMPLATE_FAILED] = 'Failed to process template "$NAME"'; + + // MSG_MIME_PREAMBLE is sent in the preamble of MIME emails + // Parameters: none + $aMessages[MSG_MIME_PREAMBLE] = '(Your mail reader should not show this ' . + 'text.\nIf it does you may need to ' . + 'upgrade to more modern software.)'; + + // MSG_MIME_HTML is sent in the preamble of HTML emails + // Parameters: + // NAME the template name + $aMessages[MSG_MIME_HTML] = 'This message has been generated by FormMail ' . + 'using an HTML template\ncalled "$NAME". The ' . + 'raw text of the form results\nhas been ' . + 'included below, but your mail reader should ' . + 'display the HTML\nversion only (unless it\'s ' . + 'not capable of doing so).'; + + // MSG_FILE_OPEN_ERROR is sent in an Alert message when FormMail + // cannot open a file + // Parameters: + // NAME the file name + // TYPE the type of file + // ERROR the system error message + $aMessages[MSG_FILE_OPEN_ERROR] = 'Failed to open $TYPE file "$NAME": $ERROR'; + + // MSG_ATTACH_DATA is sent in an Alert message when the file + // attachment through 'data' has gone wrong. + // Parameters: none + $aMessages[MSG_ATTACH_DATA] = 'Internal error: AttachFile requires ' . + '"tmp_name" or "data"'; + + // MSG_PHP_HTML_TEMPLATES is sent in an Alert message when an + // HTML template is used but the PHP version is too old. (deprecated) + // Parameters: + // $PHPVERS the current PHP version + $aMessages[MSG_PHP_HTML_TEMPLATES] = ''; + + // MSG_PHP_FILE_UPLOADS is sent in an Alert message when + // file upload is used but the PHP version is too old. (deprecated) + // Parameters: + // $PHPVERS the current PHP version + $aMessages[MSG_PHP_FILE_UPLOADS] = ''; + + // MSG_FILE_UPLOAD is sent in an Alert message when + // file upload is attempted but FormMail is not configured to allow + // it + // Parameters: none + $aMessages[MSG_FILE_UPLOAD] = 'File upload attempt ignored'; + + // MSG_FILE_UPLOAD_ATTACK is sent in an Alert message when + // possible file upload attack is detected + // Parameters: + // NAME file name + // TEMP temporary file name + // FLD name of the file upload field + $aMessages[MSG_FILE_UPLOAD_ATTACK] = 'Possible file upload attack ' . + 'detected: field="$FLD", name="$NAME" ' . + 'temp name="$TEMP"'; + + // MSG_PHP_PLAIN_TEMPLATES is sent in an Alert message when a + // Plain template is used but the PHP version is too old. (deprecated) + // Parameters: + // $PHPVERS the current PHP version + $aMessages[MSG_PHP_PLAIN_TEMPLATES] = ''; + + // MSG_ATTACH_NAME is sent in an Alert message when a + // the form uses the Attach feature without specifying a file name + // Parameters: none + $aMessages[MSG_ATTACH_NAME] = 'filter_options: Attach must contain a name ' . + '(e.g. Attach=data.txt)'; + + // MSG_PHP_BCC is sent in an Alert message when a + // the form uses the BCC feature and the PHP version may not support it + // (deprecated) + // Parameters: + // $PHPVERS the current PHP version + $aMessages[MSG_PHP_BCC] = ''; + + // MSG_CSVCOLUMNS is sent in an Alert message when a csvcolumns field + // is not correct + // Parameters: + // $VALUE the csvcolumns field value + $aMessages[MSG_CSVCOLUMNS] = 'The "csvcolumns" setting is not ' . + 'valid: "$VALUE"'; + + // MSG_CSVFILE is sent in an Alert message when a csvfile field + // is not correct + // Parameters: + // $VALUE the csvfile field value + $aMessages[MSG_CSVFILE] = 'The "csvfile" setting is not valid: "$VALUE"'; + + // MSG_TARG_EMAIL_PAT_START is sent in an Alert message when a + // $TARGET_EMAIL pattern is insecure because of a missing '^' + // at the beginning + // Parameters: + // $PAT the pattern + $aMessages[MSG_TARG_EMAIL_PAT_START] = 'Warning: Your TARGET_EMAIL pattern ' . + '"$PAT" is missing a ^ at the ' . + 'beginning.'; + + // MSG_TARG_EMAIL_PAT_END is sent in an Alert message when a + // $TARGET_EMAIL pattern is insecure because of a missing '$' + // at the end + // Parameters: + // $PAT the pattern + $aMessages[MSG_TARG_EMAIL_PAT_END] = 'Warning: Your TARGET_EMAIL pattern ' . + '"$PAT" is missing a $ at the end.'; + + // MSG_CONFIG_WARN is sent in an Alert message when the FormMail + // configuration may have some problems. The messages are + // passed on separate lines, so the line terminations below + // are important. + // Parameters: + // $MESGS lines of messages + $aMessages[MSG_CONFIG_WARN] = 'The following potential problems were found ' . + 'in your configuration:\n$MESGS\n\n' . + 'These are not necessarily errors, but you ' . + 'should review the documentation\n' . + 'inside formmail.php. If you are sure your ' . + 'configuration is correct\n' . + 'you can disable the above messages by ' . + 'changing the CONFIG_CHECK settings.'; + + // MSG_PHP_AUTORESP is sent in an Alert message when the PHP version + // does not support autoresponding (deprecated) + // Parameters: + // $PHPVERS current PHP version + $aMessages[MSG_PHP_AUTORESP] = ''; + + // MSG_ALERT is the test alert message (formmail.php?testalert=1) + // Parameters: + // $LANG the language ID + // $PHPVERS PHP version + // $FM_VERS FormMail version + // $SERVER server type + // $DOCUMENT_ROOT PHP's DOCUMENT_ROOT value + // $SCRIPT_FILENAME PHP's SCRIPT_FILENAME value + // $PATH_TRANSLATED PHP's PATH_TRANSLATED value + // $REAL_DOCUMENT_ROOT the REAL_DOCUMENT_ROOT value + $aMessages[MSG_ALERT] = 'This is a test alert message $MNUM\n' . + 'Loaded language is $LANG\n' . + 'PHP version is $PHPVERS\n' . + 'FormMail version is $FM_VERS\n' . + 'Server type: $SERVER\n' . + '\n' . + 'DOCUMENT_ROOT: $DOCUMENT_ROOT\n' . + 'SCRIPT_FILENAME: $SCRIPT_FILENAME\n' . + 'PATH_TRANSLATED: $PATH_TRANSLATED\n' . + 'REAL_DOCUMENT_ROOT: $REAL_DOCUMENT_ROOT'; + + // MSG_NO_DEF_ALERT is displayed if you use the testalert feature + // and no DEF_ALERT setting has been provided. + // Parameters: none + $aMessages[MSG_NO_DEF_ALERT] = 'No DEF_ALERT value has been set.'; + + // MSG_TEST_SENT is displayed if when use the testalert feature + // Parameters: none + $aMessages[MSG_TEST_SENT] = 'Test message sent. Check your email.'; + + // MSG_TEST_FAILED is displayed if when use the testalert feature + // and the mail sending fails. + // Parameters: none + $aMessages[MSG_TEST_FAILED] = 'FAILED to send alert message. Check your ' . + 'server error logs.'; + + // MSG_NO_DATA_PAGE is the page that's displayed if the user + // just opens the URL to FormMail directly. + // Parameters: none + $aMessages[MSG_NO_DATA_PAGE] = 'This URL is a Form submission program.\n' . + 'It appears the form is not working ' . + 'correctly as there was no data found.\n' . + 'You\'re not supposed to browse to this ' . + 'URL; it should be accessed from a form.'; + + // MSG_REQD_ERROR is displayed to the user as a default error + // message when they haven't supplied some required fields + // Parameters: none + $aMessages[MSG_REQD_ERROR] = 'The form required some values that you ' . + 'did not seem to provide.'; + + // MSG_COND_ERROR is displayed to the user as a default error + // message when some form conditions have failed + // Parameters: none + $aMessages[MSG_COND_ERROR] = 'Some of the values you provided are not valid.'; + + // MSG_CRM_FAILURE is displayed to the user when submission + // to the CRM has failed. + // Parameters: + // $URL the URL that was used + // $DATA data returned from the CRM + $aMessages[MSG_CRM_FAILURE] = 'The form submission did not succeed due to ' . + 'a CRM failure. URL was \'$URL\'. ' . + 'Returned CRM data:\n$DATA'; + + // MSG_FOPTION_WARN is sent in an Alert message when the form + // uses the superseded SendMailFOption feature + // Parameters: + // $LINE line number for SENDMAIL_F_OPTION + $aMessages[MSG_FOPTION_WARN] = 'Warning: You\'ve used SendMailFOption in ' . + '"mail_options" in your form. This has been ' . + 'superseded with a configuration setting ' . + 'inside formmail.php. Please update your ' . + 'formmail.php configuration (look for ' . + 'SENDMAIL_F_OPTION on line $LINE) and set ' . + 'it to "true", then remove SendMailFOption ' . + 'from your form(s).'; + + // MSG_NO_ACTIONS is sent in an Alert message when there is no + // action to perform or email address to send to + // Parameters: none + $aMessages[MSG_NO_ACTIONS] = 'The form has an internal error - no actions ' . + 'or recipients were specified.'; + + // MSG_NO_RECIP is sent in an Alert message when there are no + // valid recipients to send to + // Parameters: none + $aMessages[MSG_NO_RECIP] = 'The form has an internal error - no valid ' . + 'recipients were specified.'; + + // MSG_INV_EMAIL is sent in an Alert message when there are errors + // in the email addresses specified in the form + // Parameters: + // $ERRORS list of errors + $aMessages[MSG_INV_EMAIL] = 'Invalid email addresses were specified ' . + 'in the form $MNUM:\n$ERRORS'; + + // MSG_FAILED_SEND is sent in an Alert message when the mail sending fails. + // Parameters: none + $aMessages[MSG_FAILED_SEND] = 'Failed to send email'; + + // MSG_ARESP_EMAIL is sent in an Alert message when + // no email address has been specified for an autoreponse + // Parameters: none + $aMessages[MSG_ARESP_EMAIL] = 'No "email" field was found. Autorespond ' . + 'requires the submitter\'s email address.'; + + // MSG_ARESP_SUBJ is the default subject for the auto response email + // Parameters: none + $aMessages[MSG_ARESP_SUBJ] = 'Your form submission'; + + // MSG_LOG_NO_VERIMG is written to the auto respond log file + // if no VerifyImgString session variable was found + // Parameters: none + $aMessages[MSG_LOG_NO_VERIMG] = 'No VerifyImgString or turing_string in session, ' . + 'no reverse CAPTCHA, no reCaptcha'; + + // MSG_ARESP_NO_AUTH is shown to the user + // if no VerifyImgString session variable was found + // Parameters: none + $aMessages[MSG_ARESP_NO_AUTH] = 'Failed to obtain authorization to send ' . + 'you email. This is probably a fault on ' . + 'the server.'; + + // MSG_LOG_NO_MATCH is written to the auto respond log file + // if the user's entry did not match the image verification + // Parameters: none + $aMessages[MSG_LOG_NO_MATCH] = 'User did not match image'; + + // MSG_LOG_RECAPTCHA is written to the auto respond log file + // if the reCaptcha process fails + // Parameters: + // ERR the reCaptcha error code + $aMessages[MSG_LOG_RECAPTCHA] = 'reCaptcha process failed ($ERR)'; + + // MSG_ARESP_NO_MATCH is shown to the user + // if the user's entry did not match the image verification + // Parameters: none + $aMessages[MSG_ARESP_NO_MATCH] = 'Your entry did not match the image'; + + // MSG_LOG_FAILED is written to the auto respond log file + // if the autoresponding failed + // Parameters: none + $aMessages[MSG_LOG_FAILED] = 'Failed'; + + // MSG_ARESP_FAILED is sent in an Alert message + // if the autoresponding failed + // Parameters: none + $aMessages[MSG_ARESP_FAILED] = 'Autoresponder failed'; + + // MSG_LOG_OK is written to the auto respond log file + // if the autoresponding succeeded + // Parameters: none + $aMessages[MSG_LOG_OK] = 'OK'; + + // MSG_THANKS_PAGE is the default page that's displayed if the + // submission is successful + // Parameters: none + $aMessages[MSG_THANKS_PAGE] = 'Thanks! We\'ve received your information ' . + 'and, if it\'s appropriate, we\'ll be in ' . + 'contact with you soon.'; + + // MSG_LOAD_MODULE is sent in an alert message if a module + // could not be loaded. + // Parameters: + // $FILE the file name + // $ERROR the error message + $aMessages[MSG_LOAD_MODULE] = 'Cannot load module from file \'$FILE\': $ERROR'; + + // MSG_LOAD_FMCOMPUTE is sent in an alert message if the form + // specifies at least one "fmcompute" field and the FMCompute + // module cannot be loaded. + // Parameters: + // $FILE the file name + // $ERROR the error message + $aMessages[MSG_LOAD_FMCOMPUTE] = 'Cannot load FMCompute module from file ' . + '\'$FILE\': $ERROR'; + + // MSG_REGISTER_MODULE is sent in an alert message if a module + // could not register with FMCompute + // Parameters: + // $NAME the name of the module + // $ERROR the error message + $aMessages[MSG_REGISTER_MODULE] = 'Cannot register module $NAME with ' . + 'FMCompute: $ERROR'; + + // MSG_COMP_PARSE is sent in an alert message if a parse error + // occurs in an fmcompute field + // Parameters: + // $CODE the code with an error + // $ERRORS the error messages + $aMessages[MSG_COMP_PARSE] = 'These parse errors occurred in the following ' . + 'code:\n$ERRORS\n$CODE'; + + // MSG_COMP_REG_DATA is sent in an alert message if FormMail cannot + // register a data field with the FMCompute module + // Parameters: + // $NAME the field name + // $ERROR the error message + $aMessages[MSG_COMP_REG_DATA] = 'Failed to register data field \'$NAME\': ' . + '$ERROR'; + + // MSG_COMP_ALERT is sent in an alert message if the FMCompute + // module has generated some alert messages. + // Parameters: + // $ALERTS the alerts + $aMessages[MSG_COMP_ALERT] = 'The following alert messages were reported ' . + 'from the FMCompute module: $ALERTS'; + + // MSG_COMP_DEBUG is sent in an alert message if the FMCompute + // module has generated some debug messages. + // Parameters: + // $DEBUG the alerts + $aMessages[MSG_COMP_DEBUG] = 'The following debug messages were reported ' . + 'from the FMCompute module: $DEBUG'; + + // MSG_COMP_EXEC is sent in an alert message if the FMCompute + // module has generated some error messages during execution + // Parameters: + // $ERRORS the errors + $aMessages[MSG_COMP_EXEC] = 'The following error messages were reported ' . + 'from the FMCompute module: $ERRORS'; + + // MSG_TEMPL_ALERT is sent in an alert message if Advanced Template + // Processing has generated some alert messages. + // Parameters: + // $ALERTS the alerts + $aMessages[MSG_TEMPL_ALERT] = 'The following alert messages were reported ' . + 'from the Advanced Template Processor: $ALERTS'; + + // MSG_TEMPL_DEBUG is sent in an alert message if Advanced Template + // Processing has generated some debug messages. + // Parameters: + // $DEBUG the alerts + $aMessages[MSG_TEMPL_DEBUG] = 'The following debug messages were reported ' . + 'from the Advanced Template Processor: $DEBUG'; + + // MSG_TEMPL_PROC is sent in an alert message if Advanced Template Processing + // has generated some error messages during processing + // Parameters: + // $ERRORS the errors + $aMessages[MSG_TEMPL_PROC] = 'The following error messages were reported ' . + 'from the Advanced Template Processor: $ERRORS'; + + // MSG_REG_FMCOMPUTE is sent in an Alert message when FormMail + // cannot register an external function with FMCompute. + // Parameters: + // FUNC the function that could not be registered + // ERROR the error message + $aMessages[MSG_REG_FMCOMPUTE] = 'Cannot register function "$FUNC" with ' . + 'FMCompute: $ERROR'; + + // MSG_USER_ERRORS is shown as part of a user error when an FMCompute + // has called the "UserError" function one or more times. + // Parameters: + // NONE + $aMessages[MSG_USER_ERRORS] = 'One or more errors occurred in your form submission'; + + // MSG_CALL_PARAM_COUNT is sent in an alert when a call to a FormMail + // function from FMCompute has the wrong number of parameters + // Parameters: + // FUNC the function name + // COUNT the actual number of parameters passed + $aMessages[MSG_CALL_PARAM_COUNT] = 'FMCompute called FormMail function ' . + '\'$FUNC\' with wrong number of ' . + 'parameters: $COUNT'; + + // MSG_CALL_UNK_FUNC is sent in an alert when FMCompute calls an + // unknown FormMail function + // Parameters: + // FUNC the function name + $aMessages[MSG_CALL_UNK_FUNC] = 'FMCompute called unknown FormMail function ' . + '\'$FUNC\''; + + // MSG_SAVE_FILE is sent in an alert when saving a file to + // the server has failed + // Parameters: + // FILE the source file name (usually a temporary file name) + // DEST the destination file name + // ERR the error message + $aMessages[MSG_SAVE_FILE] = 'Failed to save file \'$FILE\' to \'$DEST\': $ERR'; + + // MSG_SAVE_FILE_EXISTS is sent as part of an alert when saving a file to + // the repository ($FILE_REPOSITORY) has failed because the file + // already exists and FILE_OVERWRITE is set to false. + // Parameters: + // FILE the destination file name + $aMessages[MSG_SAVE_FILE_EXISTS] = 'Cannot save file to repository as this would ' . + 'overwrite \'$FILE\' and you have ' . + 'set FILE_OVERWRITE to false.'; + + // MSG_EMPTY_ADDRESSES is sent as part of an alert when a number of empty + // email addresses have been specified in recipients, cc, or bcc + // *and* there are no valid addresses provided + // in the list + // Parameters: + // COUNT the number of empty addresses + $aMessages[MSG_EMPTY_ADDRESSES] = '$COUNT empty addresses'; + + // MSG_CALL_INVALID_PARAM is sent in an alert when a call to a FormMail + // function from FMCompute has an invalid parameter + // Parameters: + // FUNC the function name + // PARAM the parameter number + // CORRECT information about correct values + $aMessages[MSG_CALL_INVALID_PARAM] = 'FMCompute called FormMail function ' . + '\'$FUNC\' with an invalid parameter ' . + 'number $PARAM. Correct values are: $CORRECT'; + + // MSG_INI_PARSE_WARN is sent in an alert when the INI file + // may have a syntax error and cannot be parsed. + // Parameters: + // FILE the file name + $aMessages[MSG_INI_PARSE_WARN] = 'Warning: your INI file \'$FILE\' appears ' . + 'to be empty. This may indicate a syntax error.'; + + // MSG_INI_PARSE_ERROR is shown as an error message when the INI file + // has a syntax error and cannot be parsed. + // Parameters: + // FILE the file name + $aMessages[MSG_INI_PARSE_ERROR] = 'The FormMail INI file \'$FILE\' has a syntax error'; + + // MSG_CHMOD is sent in an alert when changing the protection + // mode of a file to has failed + // Parameters: + // FILE the file name + // MODE the mode + // ERR the error message + $aMessages[MSG_CHMOD] = 'Failed to change protection mode of file \'$FILE\' ' . + 'to $MODE: $ERR'; + + // MSG_VERIFY_MISSING is shown to the user image verification string + // was not found + // Parameters: none + $aMessages[MSG_VERIFY_MISSING] = 'Image verification string missing. This' . + ' is probably a fault on the server.'; + + // MSG_VERIFY_MATCH is shown to the user + // if the user's entry did not match the image verification for the + // imgverify option + // Parameters: none + $aMessages[MSG_VERIFY_MATCH] = 'Your entry did not match the image'; + + // MSG_RECAPTCHA_MATCH is shown to the user + // if using the reCaptcha system and there was an error + // Parameters: + // ERR the error code from the reCaptcha API + $aMessages[MSG_RECAPTCHA_MATCH] = 'reCaptcha verification failed ($ERR)'; + + // MSG_FILE_NAMES_INVALID is sent in an Alert message when + // a form's file_names setting has errors + // Parameters: none + // A list of errors is appended on separate lines + $aMessages[MSG_FILE_NAMES_INVALID] = 'Some file_names specifications are invalid $MNUM:\n'; + + // MSG_FILE_NAMES_NOT_FILE is sent in an Alert message when + // a form's file_names setting refers to a file field that doesn't + // exist + // Parameters: + // NAME the name of the file field that doesn't exist + $aMessages[MSG_FILE_NAMES_NOT_FILE] = 'Your file_names specification has ' . + 'an error. \'$NAME\' is not the name ' . + 'of a file upload field\n'; + + // MSG_NEXT_PLUS_GOOD is sent in an alert message if the form is + // ambiguous and specifies both "next_form" and "good_url" or + // "good_template" + // Parameters: + // $WHICH the "good_" field that was specified + $aMessages[MSG_NEXT_PLUS_GOOD] = 'The form has specified both "next_form" ' . + 'and "$WHICH" fields - the action to ' . + 'to perform is ambiguous'; + + // MSG_MULTIFORM is sent in an Alert message when a form tries + // to use a multi-form template, but templates have not been configured in + // formmail.php + // Parameters: none + $aMessages[MSG_MULTIFORM] = 'You must set either MULTIFORMDIR or MULTIFORMURL ' . + 'in formmail.php before you can use ' . + 'multi-page forms.'; + + // MSG_MULTIFORM_FAILED is sent in an Alert message + // when processing a multi-page form template has failed. + // Parameters: + // NAME the template name + $aMessages[MSG_MULTIFORM_FAILED] = 'Failed to process multi-page form template "$NAME"'; + + // MSG_NEED_THIS_FORM is sent in an Alert message + // when a multi-page form does not specify the "this_form" field. + // Parameters: + // none + $aMessages[MSG_NEED_THIS_FORM] = 'Multi-page forms require "this_form" field'; + + // MSG_NO_PHP_SELF is sent in an Alert message + // when FormMail requires the "PHP_SELF" server variable and PHP is not + // providing it. + // Parameters: + // none + $aMessages[MSG_NO_PHP_SELF] = 'PHP on the server is not providing "PHP_SELF"'; + + // MSG_RETURN_URL_INVALID is sent in an Alert message + // when "this_form" is not a valid return URL. This occurs for + // multi-page forms. + // Parameters: + // URL the invalid URL + $aMessages[MSG_RETURN_URL_INVALID] = 'Return URL "$URL" is not valid'; + + // MSG_GO_BACK is sent in an Alert message + // when "multi_go_back" has been submitted but this isn't part of a + // multi-page form. + // Parameters: + // none + $aMessages[MSG_GO_BACK] = 'Cannot "go back" if not in a multi-page form ' . + 'sequence or at the first page of the form ' . + 'sequence'; + + // MSG_OPEN_URL is sent in an Alert message when a URL cannot + // be opened. + // Parameters: + // URL the invalid URL + // ERROR error message + $aMessages[MSG_OPEN_URL] = 'Cannot open URL "$URL": $ERROR'; + + // MSG_CANNOT_RETURN is sent in an Alert message when an invalid return + // request is made in a multi-page form sequence. + // Parameters: + // TO the requested page index + // TOPINDEX the top page index + $aMessages[MSG_CANNOT_RETURN] = 'Cannot return to page $TO. The top page ' . + 'index is $TOPINDEX'; + + // MSG_ATTACK_DETECTED is sent in an Alert message when an attack on + // the server has been detected + // Parameters: + // ATTACK name or description of the attack + // INFO more information about the attack + $aMessages[MSG_ATTACK_DETECTED] = 'Server attack "$ATTACK" detected. ' . + 'Your server is safe as FormMail is ' . + 'invulnerable to this attack. You can ' . + 'disable these messages by setting ' . + 'ALERT_ON_ATTACK_DETECTION to false ' . + 'in FormMail\'s configuration section.' . + '\nMore information:\n$INFO'; + + // MSG_ATTACK_PAGE is the contents of the browser page displayed to the + // user when an attack is detected + // Parameters: + // SERVER the name of the server (website) + // USERINFO details of the error + $aMessages[MSG_ATTACK_PAGE] = 'Your form submission has been rejected ' . + 'as it appears to be an abuse of our server (' . + '$SERVER).
The following settings were found in the file '$s_file':
"; + foreach ($a_sections as $s_sect => $a_settings) { + $s_text .= "[$s_sect]\n"; + foreach ($a_settings as $s_name => $s_value) { + $s_text .= "$s_name = \"$s_value\"\n"; + } + $s_text .= "
"; + } + CreatePage($s_text,"Debug Output - INI File Display"); + FormMailExit(); + } + // + // Load the email_addresses section. + // + if (isset($a_sections["email_addresses"])) { + $a_addr_list = $a_sections["email_addresses"]; + // + // make these addresses valid + // + foreach ($a_addr_list as $s_alias => $s_list) { + $EMAIL_ADDRS[$s_alias] = $s_list; + $ValidEmails->AddAddresses($s_list); + } + } + // + // Process special fields + // + if (isset($a_sections["special_fields"])) { + foreach ($a_sections["special_fields"] as $s_name => $m_value) { + if (IsSpecialField($s_name)) { + ValidateSpecialField($s_name,$m_value,false); + SetSpecialField($s_name,$m_value); + // + // if this is the recipients, cc, or bcc field, + // make the addresses valid + // + if ($s_name === "recipients" || $s_name === "cc" || $s_name === "bcc") + // + // coming from the INI file, the values can only be strings + // + { + if (is_string($m_value)) { + $ValidEmails->AddAddresses($m_value); + } + } + } + // + // check for multiple valued special fields + // + if (($a_multi_fld = IsSpecialMultiField($s_name)) !== false) { + SetSpecialMultiField($a_multi_fld[0],$a_multi_fld[1],$m_value); + } + } + } +} + +/** + * UnMangle an email address. This means replacing AT_MANGLE in the given + * string with the @ symbol. + * It can also lookup an email alias and return the corresponding email address. + * Email aliases are defined in the EMAIL_ADDRS configuration setting or in an INI file. + * + * @param string $s_email the email address to unmangle + * + * @return string the actual email address + */ +function UnMangle($s_email) +{ + $email_addrs = Settings::get('EMAIL_ADDRS'); + + // + // map from a name to the real email address; if it exists + // + if (isset($email_addrs[$s_email])) { + $s_email = $email_addrs[$s_email]; + } + // + // unmangle + // + if (Settings::get('AT_MANGLE') != "") { + $s_email = str_replace(Settings::get('AT_MANGLE'),"@",$s_email); + } + return ($s_email); +} + +// +// Check a list of email addresses (comma separated); returns a list +// of valid email addresses (comma separated). +// The list can be an array of comma separated lists. +// The return value is true if there is at least one valid email address. +// +function CheckEmailAddress($m_addr,&$s_valid,&$s_invalid,$b_check = true) +{ + global $ValidEmails; + + $s_invalid = $s_valid = ""; + if (is_array($m_addr)) { + $a_list = array(); + foreach ($m_addr as $s_addr_list) { + $a_list = array_merge($a_list,TrimArray(explode(",",$s_addr_list))); + } + } else { + $a_list = TrimArray(explode(",",$m_addr)); + } + $a_invalid = array(); + $n_empty = 0; + for ($ii = 0 ; $ii < count($a_list) ; $ii++) { + if ($a_list[$ii] === "") { + // + // ignore, but count empty addresses + // + $n_empty++; + continue; + } + $s_email = UnMangle($a_list[$ii]); + // + // UnMangle works with INI files too, and a single + // word can expand to a list of email addresses. + // + $a_this_list = TrimArray(explode(",",$s_email)); + foreach ($a_this_list as $s_email) { + if ($s_email === "") { + // + // ignore, but count empty addresses + // + $n_empty++; + continue; + } + if ($b_check) { + $b_is_valid = $ValidEmails->CheckAddress($s_email); + } else { + $b_is_valid = true; + } + if ($b_is_valid) { + if (empty($s_valid)) { + $s_valid = $s_email; + } else { + $s_valid .= "," . $s_email; + } + } else { + $a_invalid[] = $s_email; + } + } + } + // + // just ignore empty recipients unless there are *no* valid recipients + // + if (empty($s_valid) && $n_empty > 0) { + $a_invalid[] = GetMessage(MSG_EMPTY_ADDRESSES,array("COUNT" => $n_empty)); + } + if (count($a_invalid) > 0) { + $s_invalid = implode(",",$a_invalid); + } + return (!empty($s_valid)); +} + +// +// PHP 8 replacement for +// filter_var($url,FILTER_SANITIZE_STRING) +// See: https://stackoverflow.com/questions/69207368/constant-filter-sanitize-string-is-deprecated +// +function filter_string_polyfill(string $string): string +{ + $str = preg_replace('/\x00|<[^>]*>?/','',$string); + return str_replace(["'",'"'],[''','"'],$str); +} + +// +// Redirect to another URL +// +function Redirect($url,$title) +{ + global $ExecEnv; + + // + // for browsers without cookies enabled, append the Session ID + // + if ($ExecEnv->allowSessionURL()) { + if (session_id() !== "") { + $url = AddURLParams($url,session_name() . "=" . urlencode(session_id())); + } elseif (defined("SID")) { + $url = AddURLParams($url,SID); + } + } + + //FMDebug("Before redirecting, FormData = ".(isset($_SESSION["FormData"]) ? var_export($_SESSION["FormData"],true) : "NULL")); + + // + // this is probably a good idea to ensure the session data + // is written away + // + if (function_exists('session_write_close')) { + session_write_close(); + } + + header("Location: $url"); + + // + // avoid XSS by sanitizing the URL + // + $url = stripJS(filter_string_polyfill($url)); + + // + // if the header doesn't work, try JavaScript. + // if that doesn't work, provide a manual link + // + $s_text = GetMessage(MSG_PLSWAIT_REDIR) . "\n\n"; + $s_text .= ""; + $s_text .= "\n\n" . GetMessage(MSG_IFNOT_REDIR,array("URL" => $url)); + CreatePage($s_text,$title); + FormMailExit(); +} + +/** + * Remove 'javascript:' from the given text. + * + * @param string $s_text the text to be modified + * + * @return string|string[] + */ +function stripJS($s_text) +{ + return str_ireplace('javascript:','',$s_text); +} + +class JSON +{ + function _Format($m_val) + { + if (is_bool($m_val)) { + $s_value = ($m_val) ? "true" : "false"; + } elseif (is_string($m_val)) { + // + // convert literal line breaks into JavaScript escape sequences + // + $s_value = '"' . str_replace(array("\r","\n"),array('\\r','\\n'),addslashes($m_val)) . '"'; + } elseif (is_numeric($m_val)) { + $s_value = $m_val; + } elseif (is_array($m_val)) { + $s_value = $this->_FormatArray($m_val); + } else { + $s_value = "null"; + } + return ($s_value); + } + + function _FormatArray($a_array) + { + if ($this->_IsNumericArray($a_array)) { + $a_values = array(); + foreach ($a_array as $m_val) { + $a_values[] = $this->_Format($m_val); + } + $s_value = "[" . implode(",",$a_values) . "]"; + } else { + // + // associative arrays are objects + // + $s_value = $this->MakeObject($a_array); + } + return ($s_value); + } + + // + // check if we have a numeric array or an associative array + // numeric arrays may have holes; numeric array indexes must + // be integers + // + function _IsNumericArray($a_data) + { + if (empty($a_data)) { + return (true); + } // empty array - treat as numeric + // + // check all the keys for numeric + // + $a_keys = array_keys($a_data); + foreach ($a_keys as $m_index) { + if (!is_int($m_index)) { + return (false); + } + } + return (true); + } + + function MakeObject($a_data) + { + $a_members = array(); + foreach ($a_data as $s_key => $m_val) { + $a_members[] = '"' . $s_key . '":' . $this->_Format($m_val); + } + return ("{" . implode(",",$a_members) . "}"); + } +} + +function CORS_Response() +{ + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Max-Age: 36000'); + header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); + header('Access-Control-Allow-Headers: X-Requested-With'); +} + +function JSON_Result($s_result,$a_data = array()) +{ + global $aGetVars; + + FMDebug("Sending JSON_Result: $s_result"); + $a_data["Result"] = $s_result; + $json = new JSON(); + $s_ret = $json->MakeObject($a_data); + CORS_Response(); + // + // handle JSONP request + // + if (isset($aGetVars['callback']) && $aGetVars['callback'] != '') { + header('Content-Type: text/javascript; charset=utf-8'); + $s_ret = $aGetVars['callback'] . "($s_ret);"; + FMDebug('JSONP request callback=' . $aGetVars['callback']); + } else { + header('Content-Encoding: utf-8'); + header('Content-Type: application/json; charset=utf-8'); + } + FMDebug("JSON_Result output: " . $s_ret); + echo $s_ret; +} + +// +// JoinLines is just like "implode" except that it checks +// the end of each array for the separator already being +// there. This allows us to join a mixture of mail +// header lines (already terminated) with body lines. +// This logic works if HEAD_CRLF, for example, is the same +// as BODY_LF (i.e. both "\r\n") or if BODY_LF is the +// same as the last character in HEAD_CRLF (i.e. +// HEAD_CRLF = "\r\n" and BODY_LF = "\n"). +// Other value combinations may break things. +// +function JoinLines($s_sep,$a_lines) +{ + $s_str = ""; + if (($i_sep_len = strlen($s_sep)) == 0) + // + // no separator + // + { + return (implode("",$a_lines)); + } + $n_lines = count($a_lines); + for ($ii = 0 ; $ii < $n_lines ; $ii++) { + $s_line = $a_lines[$ii]; + if (substr($s_line,-$i_sep_len) == $s_sep) { + $s_str .= $s_line; + } else { + $s_str .= $s_line; + // + // don't append a separator to the last line + // + if ($ii < $n_lines - 1) { + $s_str .= $s_sep; + } + } + } + return ($s_str); +} + +// +// Re-orders an array of email headers into the +// order recommended by RFC822, section 4.1: +// It is recommended that, if present, +// headers be sent in the order "Return- +// Path", "Received", "Date", "From", "Subject", +// "Sender", "To", "cc", etc. +// +// Note that RFC822 is obsoleted by RFC2822 and +// the latter states that field order doesn't +// matter (except for some tracing fields). +// However, a FormMail user reported that Yahoo doesn't like +// email where the CC header appears before the From +// header. So, as always, we try to work with broken +// servers too... +// +// Returns an array indexed by the require numerical +// order. Each element is an array containing the +// header value (name,value pair). +// +function OrderHeaders($a_headers) +{ + // + // we list the headers we're responsible for + // in the order suggested + // + $a_ordering = array("From","Subject","To","Cc","Bcc","Reply-To"); + $a_ordered_headers = array(); + foreach ($a_ordering as $s_name) { + if (isset($a_headers[$s_name])) { + $a_ordered_headers[] = array($s_name => $a_headers[$s_name]); + unset($a_headers[$s_name]); + } + } + // + // now add in the remaining headers + // + foreach ($a_headers as $s_name => $s_value) { + $a_ordered_headers[] = array($s_name => $a_headers[$s_name]); + } + return ($a_ordered_headers); +} + +// +// Makes a mail header field body "safe". +// This simply places a backslash in front of every double-quote. +// There's probably more we could do if required, but this +// attempts to provide the same protection that was in the first +// version of FormMail. In that version, every incoming +// field had double-quotes replaced with single quotes. +// That processing is no longer performed, and this +// function is used to protect against potential attacks in +// header fields - not by replacing double quotes with single quotes, +// but by using the backslash "quoting" feature of RFC2822. +// +// This code could be improved by parsing the header and rewriting +// it to be valid, possibly removing junk. +// +// That's a lot of code, though! +// +function SafeHeader($s_str) +{ + return (str_replace('"','\\"',$s_str)); +} + +// +// makes a string safe to put as words in a header +// +function SafeHeaderWords($s_str) +{ + // + // We zap various characters and replace them with a question mark. + // Also, we don't handle quoted strings, which are valid words. + // + $s_specials = '()<>@,;:\\".[]'; // special characters defined by RFC822 + $s_str = preg_replace('/[[:cntrl:]]+/',"?",$s_str); // zap all control chars + $s_str = preg_replace("/[" . preg_quote($s_specials,"/") . "]/","?",$s_str); // zap all specials + return ($s_str); +} + +// +// makes a string safe to put as a quoted string in a header +// +function SafeHeaderQString($s_str) +{ + return (str_replace('"','\\"', + str_replace("\\","\\\\", + str_replace("\r"," ", + str_replace("\r\n"," ",$s_str))))); +} + +// +// makes a string safe to put in a header comment +// +function SafeHeaderComment($s_str) +{ + return (str_replace("(","\\(", + str_replace(")","\\)", + str_replace("\\","\\\\", + str_replace("\r"," ", + str_replace("\r\n"," ",$s_str)))))); +} + +// +// makes a string safe to put in a header as an email address +// +function SafeHeaderEmail($s_str) +{ + // + // An email address is made up of local and domain parts + // each of these is made up of "words" separated by "." + // each "word" can be a sequence of characters excluding + // specials, space and control characters OR it can be + // a quoted string. + // + // The correct processing would be to completely + // parse the address, strip junk, double-quote + // words that need to be turned into quote strings, + // and return a well-formed email address. + // + // That's a lot of code! + // + // So, instead, we opt for stripping out control characters. + // + $s_str = preg_replace('/[[:cntrl:]]+/',"",$s_str); // zap all control chars + return ($s_str); +} + +// +// Expands an array of mail headers into mail header lines. +// +function ExpandMailHeaders($a_headers,$b_fold = false) +{ + $s_hdrs = ""; + $a_ordered_headers = OrderHeaders($a_headers); + for ($ii = 0 ; $ii < count($a_ordered_headers) ; $ii++) { + foreach ($a_ordered_headers[$ii] as $s_name => $s_value) { + if ($s_name != "") { + if ($s_hdrs != "") { + $s_hdrs .= Settings::get('HEAD_CRLF'); + } + if ($b_fold) { + $s_hdrs .= HeaderFolding($s_name . ": " . $s_value); + } else { + $s_hdrs .= $s_name . ": " . $s_value; + } + } + } + } + //FMDebug("Headers are: $s_hdrs"); + return ($s_hdrs); +} + +// +// Expands an array of mail headers into an array containing header lines. +// +function ExpandMailHeadersArray($a_headers) +{ + $a_hdrs = array(); + $a_ordered_headers = OrderHeaders($a_headers); + for ($ii = 0 ; $ii < count($a_ordered_headers) ; $ii++) { + foreach ($a_ordered_headers[$ii] as $s_name => $s_value) { + if ($s_name != "") { + $a_hdrs[] = $s_name . ": " . $s_value . Settings::get('HEAD_CRLF'); + } + } + } + return ($a_hdrs); +} + +// +// Low-level email send function; either calls PHP's mail function +// or uses the PEAR Mail object. +// NOTE: for some errors, there's no point trying to email +// an alert message! So, in these cases, we just display the error to +// the user. +// $s_options are ignored for PEAR sending. +// +function DoMail($s_to,$s_subject,$s_mesg,$a_headers,$s_options) +{ + global $ALT_MAIL_FUNCTION; + + if ($ALT_MAIL_FUNCTION !== '') { + return ($ALT_MAIL_FUNCTION($s_to,$s_subject,$s_mesg,$a_headers,$s_options)); + } else { + // + // Encode the subject line. + // Ideally, we want to encode the relevant parts of To, From, Cc, + // Reply-To, and this is the right place to do it. + // However, it's another 1000 lines of code! + // So, we must compromise the code quality because of this cost. + // We encode subject here, and we encode the From line where it's + // created. The rest remain for a future version where code size + // can be controlled. + // + $s_subject = EncodeHeaderText($s_subject); + if (!Settings::isEmpty('PEAR_SMTP_HOST')) { + // + // Note that PEAR Mail seems to take responsibility for header line folding + // + require_once("Mail.php"); + + $a_params = array("host" => Settings::get('PEAR_SMTP_HOST'), + "port" => Settings::get('PEAR_SMTP_PORT') + ); + if (!Settings::isEmpty('PEAR_SMTP_USER')) { + $a_params["auth"] = TRUE; + $a_params["username"] = Settings::get('PEAR_SMTP_USER'); + $a_params["password"] = Settings::get('PEAR_SMTP_PWD'); + } + $mailer = Mail::factory("smtp",$a_params); + if (!is_object($mailer)) { + ShowError("pear_error",GetMessage(MSG_PEAR_OBJ),FALSE,FALSE); + FormMailExit(); + } + if (strtolower(get_class($mailer)) === 'pear_error') { + ShowError("pear_error",$mailer->getMessage(),FALSE,FALSE); + FormMailExit(); + } + if (!isset($a_headers['To']) && !isset($a_headers['to'])) { + $a_headers['To'] = SafeHeader($s_to); + } + if (!isset($a_headers['Subject']) && !isset($a_headers['subject'])) { + $a_headers['Subject'] = SafeHeader($s_subject); + } + $res = $mailer->send($s_to,$a_headers,$s_mesg); + if ($res === TRUE) { + return (TRUE); + } + + global $aAlertInfo; + + $aAlertInfo[] = GetMessage(MSG_PEAR_ERROR,array("MSG" => $res->getMessage())); + return (FALSE); + } else { + //$s_subject = HeaderFolding($s_subject,RFCLINELEN-10); // "Subject: " is about 10 chars + // + // Notes from Feb 2010.... + // + // PHP's mail function (tested in version 5.2.6) does folding of the + // To line and the Subject line. + // If we do it, then things break. + // + // This area is quite confusing. It's not clear whether the script + // should be folding header lines or whether the MTA should do it. + // We *do know* (as stated above) that folding To and Subject breaks things. + // + // But folding other header lines properly, seems to be OK. + // + // However, for years FormMail never did header line folding (except for the + // soft line breaks inserted by the quoted_printable_encode function we had used), + // and we didn't seem to get any reports of breakage (except for problems + // with the quoted_printable_encode soft line breaks!). + // + // So, even though we've implemented all the code for header line folding, + // we'll not use it. + // No header line folding will be performed in version 8.22 onwards. + // + if ($s_options !== "") { + return (mail($s_to,$s_subject,$s_mesg,ExpandMailHeaders($a_headers),$s_options)); + } else { + return (mail($s_to,$s_subject,$s_mesg,ExpandMailHeaders($a_headers))); + } + } + } +} + +// +// Send an email +// +function SendCheckedMail($to,$subject,$mesg,$sender,$a_headers = array()) +{ + + $b_f_option = false; + $b_form_option = IsMailOptionSet("SendMailFOption"); // this is superseded, but still supported + if (Settings::get('SENDMAIL_F_OPTION') || $b_form_option) { + if (empty($sender)) { + // + // SENDMAIL_F_OPTION with no sender is silently ignored + // + if ($b_form_option) { + // + // form has specified SendMailFOption, but there's no + // sender address + // + static $b_in_here = false; + global $SERVER; + + if (!$b_in_here) // prevent infinite recursion + { + $b_in_here = true; + SendAlert(GetMessage(MSG_NO_FOPT_ADDR)); + $b_in_here = false; + } + // + // if there's no from address, create a dummy one + // + $sender = "dummy@" . (isset($SERVER) ? $SERVER : "UnknownServer"); + $a_headers['From'] = $sender; + $b_f_option = true; + } + } else { + $b_f_option = true; + } + } + if (Settings::get('INI_SET_FROM') && !empty($sender)) { + ini_set('sendmail_from',$sender); + } + + return (DoMail($to,$subject,$mesg,$a_headers,($b_f_option ? "-f$sender" : ""))); +} + +// +// Send an alert email, but not if ATTACK_DETECTION_IGNORE_ERRORS is true. +// +function SendAlertIgnoreSpam($s_error,$b_filter = true,$b_non_error = false) +{ + if (!Settings::get('ATTACK_DETECTION_IGNORE_ERRORS')) { + SendAlert($s_error,$b_filter,$b_non_error); + } +} + +// +// Send an alert email +// +function SendAlert($s_error,$b_filter = true,$b_non_error = false,$s_addl_subject = '') +{ + global $SPECIAL_VALUES,$FORMATTED_INPUT,$aServerVars,$aStrippedFormVars; + global $aAlertInfo,$aCleanedValues,$aFieldOrder,$sHTMLCharSet; + + // + // The following initialisations are so that ShowError can run from fmhookpreinit scripts + // + $aSpecialValues = isset($SPECIAL_VALUES) ? $SPECIAL_VALUES : array(); + $aFormattedInputValues = isset($FORMATTED_INPUT) ? $FORMATTED_INPUT : array(); + $aServerVarValues = isset($aServerVars) ? $aServerVars : array(); + $aStrippedFormVarValues = isset($aStrippedFormVars) ? $aStrippedFormVars : array(); + $aAlertInfoValues = isset($aAlertInfo) ? $aAlertInfo : array(); + $aCleaned = isset($aCleanedValues) ? $aCleanedValues : array(); + $aFieldOrderValues = isset($aFieldOrder) ? $aFieldOrder : array(); + + $s_error = str_replace("\n",Settings::get('BODY_LF'),$s_error); + $b_got_filter = GetFilterSpec($s_filter_name,$a_filter_list); + + // + // if there is a filter specified and we're not sending the alert + // through the filter, don't show the user's data. This is + // on the assumption that the filter is an encryption program; so, + // we don't want to send the user's data in clear text inside the + // alerts. + // + $b_show_data = true; + if ($b_got_filter && !$b_filter) { + $b_show_data = false; + } + + $s_form_subject = $s_alert_to = ""; + $b_check = true; + // + // might be too early to have $aSpecialValues set, so + // look in the form vars too + // + if (isset($aSpecialValues["alert_to"])) { + $s_alert_to = trim($aSpecialValues["alert_to"]); + } + if (empty($s_alert_to) && isset($aStrippedFormVarValues["alert_to"])) { + $s_alert_to = trim($aStrippedFormVarValues["alert_to"]); + } + + if (isset($aSpecialValues["subject"])) { + $s_form_subject = trim($aSpecialValues["subject"]); + } + if (empty($s_form_subject) && isset($aStrippedFormVarValues["subject"])) { + $s_form_subject = trim($aStrippedFormVarValues["subject"]); + } + + if (empty($s_alert_to)) { + $s_alert_to = Settings::get('DEF_ALERT'); + $b_check = false; + } + if (!empty($s_alert_to)) { + $s_from_addr = $s_from = ""; + $a_headers = array(); + if (!Settings::isEmpty('FROM_USER')) { + if (Settings::get('FROM_USER') != "NONE") { + $a_headers['From'] = Settings::get('FROM_USER'); + $s_from_addr = Settings::get('FROM_USER'); + $s_from = "From: $s_from_addr"; + } + } else { + global $SERVER; + + $s_from_addr = "FormMail@" . $SERVER; + $a_headers['From'] = $s_from_addr; + $s_from = "From: $s_from_addr"; + } + $s_mesg = "To: " . UnMangle($s_alert_to) . Settings::get('BODY_LF'); + // + // if a language pack has been included, a lot of error messages + // may need the character set to be provided. + // If that's available from the language pack, use it, + // otherwise, if it's a mail_option, use it from there. + // + $s_charset = ""; + if (isset($sHTMLCharSet) && $sHTMLCharSet !== "") { + $s_charset = $sHTMLCharSet; + } else { + if (IsMailOptionSet("CharSet")) { + $s_charset = GetMailOption("CharSet"); + } + } + + // + // Alerts are plain text emails, so convert any HTML entities + // back to their original characters. Note, this will only work on PHP + // version 4.3.0 and above. + // + if (function_exists("html_entity_decode")) { + $s_error = @html_entity_decode($s_error,ENT_COMPAT,$s_charset); + } + + if ($s_charset !== "") { + $a_headers['Content-Type'] = SafeHeader("text/plain; charset=$s_charset"); + } + + if (!empty($s_from)) { + $s_mesg .= $s_from . Settings::get('BODY_LF'); + } + $s_mesg .= Settings::get('BODY_LF'); + if (count($aAlertInfoValues) > 0) { + if ($b_show_data) { + $s_error .= Settings::get('BODY_LF') . GetMessage(MSG_MORE_INFO) . Settings::get('BODY_LF'); + $s_error .= implode(Settings::get('BODY_LF'),$aAlertInfoValues); + } else { + $s_error .= Settings::get('BODY_LF') . GetMessage(MSG_INFO_STOPPED) . Settings::get('BODY_LF'); + } + } + // + // some fields aren't security issues - show those in the alert + // + $a_safe_fields = array( + "email: " . isset($aSpecialValues["email"]) ? $aSpecialValues["email"] : '', + "realname: " . isset($aSpecialValues["realname"]) ? $aSpecialValues["realname"] : '', + ); + $s_safe_data = implode(Settings::get('BODY_LF'),$a_safe_fields); + + if ($b_non_error) { + $s_preamble = $s_error . Settings::get('BODY_LF') . Settings::get('BODY_LF'); + $s_mesg .= $s_preamble; + $s_subj = GetMessage(MSG_FM_ALERT) . ($s_addl_subject !== '' ? " - $s_addl_subject" : ''); + if (!empty($s_form_subject)) { + $s_subj .= " ($s_form_subject)"; + } + } else { + $s_preamble = GetMessage(MSG_FM_ERROR_LINE) . Settings::get('BODY_LF') . + $s_error . Settings::get('BODY_LF') . Settings::get('BODY_LF'); + $s_mesg .= $s_preamble; + $s_subj = GetMessage(MSG_FM_ERROR) . ($s_addl_subject !== '' ? " - $s_addl_subject" : ''); + if (!empty($s_form_subject)) { + $s_subj .= " ($s_form_subject)"; + } + $s_mesg .= $s_safe_data; + $s_mesg .= Settings::get('BODY_LF') . Settings::get('BODY_LF'); + if ($b_show_data) { + $s_mesg .= implode(Settings::get('BODY_LF'),$aFormattedInputValues); + } else { + $s_mesg .= GetMessage(MSG_USERDATA_STOPPED); + } + } + + /* + * We only need to filter the form fields if the filter that + * is specified is an encrypting filter. + */ + if ($b_filter && $b_got_filter && + IsFilterAttribSet($aSpecialValues["filter"],"Encrypts") + ) { + $s_new_mesg = $s_preamble . $s_safe_data; + $s_new_mesg .= Settings::get('BODY_LF') . Settings::get('BODY_LF'); + + if ($a_filter_list !== false) { + // + // just filter the critical fields + // + list($s_unfiltered,$s_filtered_results) = + GetFilteredOutput($aFieldOrderValues,$aCleaned, + $s_filter_name,$a_filter_list); + $s_new_mesg .= $s_unfiltered; + } else { + // + // filter everything + // + $s_filtered_results = Filter($s_filter_name,$s_mesg); + } + $s_new_mesg .= GetMessage(MSG_FILTERED,array("FILTER" => $s_filter_name)) . + Settings::get('BODY_LF') . Settings::get('BODY_LF') . + $s_filtered_results; + $s_mesg = $s_new_mesg; + } + $s_mesg .= Settings::get('BODY_LF'); + + if (isset($aServerVarValues['HTTP_REFERER'])) { + $s_mesg .= "Referring page was " . $aServerVarValues['HTTP_REFERER']; + } elseif (isset($aSpecialValues['this_form']) && $aSpecialValues['this_form'] !== "") { + $s_mesg .= "Referring form was " . $aSpecialValues['this_form']; + } + + $s_mesg .= Settings::get('BODY_LF'); + + if (isset($aServerVarValues['SERVER_NAME'])) { + $s_mesg .= "SERVER_NAME was " . $aServerVarValues['SERVER_NAME'] . Settings::get('BODY_LF'); + } + if (isset($aServerVarValues['REQUEST_URI'])) { + $s_mesg .= "REQUEST_URI was " . $aServerVarValues['REQUEST_URI'] . Settings::get('BODY_LF'); + } + + $s_mesg .= Settings::get('BODY_LF'); + + if (isset($aServerVarValues['REMOTE_ADDR'])) { + $s_mesg .= "User IP address was " . $aServerVarValues['REMOTE_ADDR'] . Settings::get('BODY_LF'); + } + if (isset($aServerVarValues['HTTP_USER_AGENT'])) { + $s_mesg .= "User agent was " . $aServerVarValues['HTTP_USER_AGENT'] . Settings::get('BODY_LF'); + } + + if ($b_check) { + if (CheckEmailAddress($s_alert_to,$s_valid,$s_invalid)) { + return (SendCheckedMail($s_valid,$s_subj,$s_mesg,$s_from_addr,$a_headers)); + } + } else { + return (SendCheckedMail($s_alert_to,$s_subj,$s_mesg,$s_from_addr,$a_headers)); + } + } + return (false); +} + +// +// Read the lines in a file and return an array. +// Each line is stripped of line termination characters. +// +function ReadLines($fp) +{ + $a_lines = array(); + while (!feof($fp)) { + $s_line = fgets($fp,4096); + // + // strip carriage returns and line feeds + // + $s_line = str_replace("\r","",$s_line); + $s_line = str_replace("\n","",$s_line); + $a_lines[] = $s_line; + } + return ($a_lines); +} + +// +// Open a URL and return the data from it as a string or array of lines. +// Returns false on failure ($s_error has the error string) +// +function GetURL($s_url,&$s_error,$b_ret_lines = false,$n_depth = 0) +{ + global $php_errormsg,$aServerVars,$sUserAgent,$ExecEnv; + + // + // open the URL with the same session as we have + // + if ($ExecEnv->allowSessionURL()) { + if (session_id() !== "") { + $s_url = AddURLParams($s_url,session_name() . "=" . urlencode(session_id())); + } + if (defined("SID")) { + $s_url = AddURLParams($s_url,SID); + } + } + + $http_get = new HTTPGet($s_url); + + // + // Determine authentication requirements + // + if (Settings::get('AUTHENTICATE') !== "" || Settings::get('AUTH_USER') !== "" || Settings::get('AUTH_PW') !== "") { + if (Settings::get('AUTHENTICATE') === "") { + $http_get->SetAuthentication("Basic",Settings::get('AUTH_USER'),Settings::get('AUTH_PW')); + } else { + $http_get->SetAuthenticationLine(Settings::get('AUTHENTICATE')); + } + } else { + $a_parts = $http_get->GetURLSplit(); + if (isset($a_parts["user"]) || isset($a_parts["pass"])) { + $s_auth_user = isset($a_parts["user"]) ? $a_parts["user"] : ""; + $s_auth_pass = isset($a_parts["pass"]) ? $a_parts["pass"] : ""; + } else { + $s_auth_type = isset($aServerVars["PHP_AUTH_TYPE"]) ? $aServerVars["PHP_AUTH_TYPE"] : ""; + $s_auth_user = isset($aServerVars["PHP_AUTH_USER"]) ? $aServerVars["PHP_AUTH_USER"] : ""; + $s_auth_pass = isset($aServerVars["PHP_AUTH_PW"]) ? $aServerVars["PHP_AUTH_PW"] : ""; + } + if (!isset($s_auth_type) || $s_auth_type === "") { + $s_auth_type = "Basic"; + } + if ($s_auth_user !== "" || $s_auth_pass !== "") { + $http_get->SetAuthentication($s_auth_type,$s_auth_user,$s_auth_pass); + } + } + // + // set the user agent + // + $http_get->SetAgent($sUserAgent); + // + // resolve the name now so the DNS cache can be written to the session + // + $http_get->Resolve(); + + // + // Since we might be opening a URL within the same session, we can + // get locks. So, close the session for writing to prevent this. + // + $b_closed = false; + if (function_exists('session_write_close')) { + session_write_close(); + $b_closed = true; + //ob_flush(); // this prevents automatic redirects if $TEMPLATEURL + // is in use and JavaScript is switched off + } + + $m_buf = FALSE; + + //FMDebug("Begin read"); + if (($a_lines = $http_get->Read()) === FALSE) { + $http_get->Close(); + // + // get the error code and send the appropriate alert + // + list($i_error,$i_sys_err,$s_sys_msg) = $http_get->GetError(); + switch ($i_error) { + case $http_get->nErrParse: + $s_error = GetMessage(MSG_URL_PARSE); + break; + case $http_get->nErrScheme: + $a_parts = $http_get->GetURLSplit(); + $s_error = GetMessage(MSG_URL_SCHEME,array("SCHEME" => $a_parts["scheme"])); + break; + default: + $s_error = GetMessage(MSG_SOCKET, + array("ERRNO" => $i_sys_err, + "ERRSTR" => $s_sys_msg, + "PHPERR" => isset($php_errormsg) ? $php_errormsg : "" + )); + break; + } + } else { + $http_get->Close(); + // + // check the HTTP response for actual status. Anything outside + // 200-299 is a failure, but we also handle redirects. + // + list($i_http_code,$s_http_status) = $http_get->GetHTTPStatus(); + + if ($i_http_code < 200 || $i_http_code > 299) { + switch ($i_http_code) { + case 300: // multiple choices (we'll take the first) + case 301: // moved permanently + case 302: // found + case 303: // see other + /** @noinspection PhpMissingBreakStatementInspection */ + case 307: // temporary redirect + // + // a "location" header must be present for us to continue + // In the case of infinite redirects, we need to stop. + // So, we limit to a maximum of 10 redirects. + // + if ($n_depth < 10) { + if (($s_location = $http_get->FindHeader("location")) !== false) { + FMDebug("Redirect from '$s_url' to '$s_location'"); + $m_buf = GetURL($s_location,$s_error,$b_ret_lines,$n_depth + 1); + $b_closed = false; + break; + } + FMDebug("Redirect FAILED - no location header"); + } else { + FMDebug("Redirect FAILED depth=$n_depth"); + } + // FALL THRU + default: + $s_error = GetMessage(MSG_GETURL_OPEN,array("STATUS" => $s_http_status,"URL" => $s_url)); + break; + } + } elseif ($b_ret_lines) { + $m_buf = $a_lines; + } else + // + // return lines as one big string buffer + // + { + $m_buf = implode("",$a_lines); + } + } + // + // re-open our session + // + if ($b_closed) { + session_start(); + } + + return ($m_buf); +} + +// +// Write to the debug log if it exists and is writable. +// +function FMDebug($s_mesg) +{ + static $fDebug = NULL; + + if (!isset($fDebug)) { + $fDebug = false; // only initialize once + $s_db_file = "fmdebug.log"; // look for debug file in current directory + // + // we only open an existing file - we don't create one + // + if (file_exists($s_db_file)) { + if (($fDebug = fopen($s_db_file,"a")) === false) { + return; + } + } + } + if ($fDebug !== false) { + fwrite($fDebug,date('r') . ": " . $s_mesg . "\n"); + fflush($fDebug); + } +} + +/* + * Class: NetIO + * Description: + * A class to provide internet input/output capabilities. + * Use as a base class for more specific functions. + */ + +class NetIO +{ + var $_sHost; + var $_iPort; + var $_sPrefix; + + var $_iConnTimeout; + var $_fSock; + + var $_aIPs; + + var $_iError = 0; + var $_iSysErr; + var $_sSysMesg; + + var $nErrInit = -1; // not initialized + var $nErrRead = -2; // read error + var $nErrWrite = -3; // write error + var $nErrWriteShort = -4; // failed to write all bytes + + var $nErrSocket = -100; // error in socket open + + function __construct($s_host = NULL,$i_port = NULL,$s_prefix = "") + { + if (isset($s_host)) { + $this->_sHost = $s_host; + } + if (isset($i_port)) { + $this->_iPort = $i_port; + } + $this->_sPrefix = $s_prefix; + $this->_iConnTimeout = 30; + $this->_iSysErr = 0; + $this->_sSysMesg = ""; + } + + function _SetError($i_error,$i_sys_err = 0,$s_sys_mesg = "") + { + $this->_iError = $i_error; + $this->_iSysErr = $i_sys_err; + $this->_sSysMesg = $s_sys_mesg; + return (FALSE); + } + + function IsError() + { + return $this->_iError !== 0; + } + + function ClearError() + { + $this->_SetError(0); + } + + function GetError() + { + return (array($this->_iError,$this->_iSysErr,$this->_sSysMesg)); + } + + function SetHost($s_host) + { + $this->_sHost = $s_host; + } + + function SetPort($i_port) + { + $this->_iPort = $i_port; + } + + function SetConnectionTimeout($i_secs) + { + $this->_iConnTimeout = $i_secs; + } + + function SetPrefix($s_prefix) + { + $this->_sPrefix = $s_prefix; + } + + function GetHost() + { + return (isset($this->_sHost) ? $this->_sHost : ""); + } + + function GetPort() + { + return (isset($this->_iPort) ? $this->_iPort : 0); + } + + function GetPrefix() + { + return ($this->_sPrefix); + } + + function GetConnectionTimeout() + { + return ($this->_iConnTimeout); + } + + function _CacheIt() + { + FMDebug("Caching " . implode(",",$this->_aIPs)); + if (IsSetSession("FormNetIODNSCache")) { + $a_cache = GetSession("FormNetIODNSCache"); + } else { + $a_cache = array(); + } + $a_cache[$this->_sHost] = $this->_aIPs; + SetSession("FormNetIODNSCache",$a_cache); + } + + /* + * Some versions of PHP seem to have a major slowdown when resolving + * names with gethostbyname (5 seconds with PHP 4.3.9). + * So, in the case of multi-page forms using MULTIFORMURL, we get a big speed up + * by caching the IP address of the server. + */ + function _CheckCache() + { + if (!IsSetSession("FormNetIODNSCache")) { + return (FALSE); + } + $a_cache = GetSession("FormNetIODNSCache"); + if (!is_array($a_cache) || !isset($a_cache[$this->_sHost]) || !is_array($a_cache[$this->_sHost])) { + return (FALSE); + } + $this->_aIPs = $a_cache[$this->_sHost]; + return (TRUE); + } + + function Resolve() + { + $this->ClearError(); + if (!isset($this->_sHost)) { + return ($this->_SetError($this->nErrInit)); + } + if ($this->_CheckCache()) { + return (TRUE); + } + FMDebug("Start resolve of " . $this->_sHost); + // + // if host is an actual IP address, then it is returned unchanged, which is good! + // + if (($a_ip_list = gethostbynamel($this->_sHost)) === FALSE) { + FMDebug("Resolve failed"); + return ($this->_SetError($this->nErrInit,0, + GetMessage(MSG_RESOLVE,array("NAME" => $this->_sHost)))); + } + FMDebug("Done resolve: " . implode(",",$a_ip_list)); + $this->_aIPs = $a_ip_list; + $this->_CacheIt(); + return (TRUE); + } + + function _SSLOpen($s_ip,&$errno,&$errstr,$i_timeout) + { + global $ExecEnv; + + FMDebug("Using _SSLOpen (stream_socket_client), SNI, host=" . $this->GetHost()); + $context = stream_context_create(); + $result = stream_context_set_option($context,'ssl','verify_host',true); + $result = stream_context_set_option($context,'ssl','verify_peer',false); + $result = stream_context_set_option($context,'ssl','allow_self_signed',true); + $result = stream_context_set_option($context,'ssl','SNI_enabled',true); + if ($ExecEnv->IsPHPAtLeast("5.6.0")) { + $result = stream_context_set_option($context,'ssl','peer_name',$this->GetHost()); + } else { + $result = stream_context_set_option($context,'ssl','SNI_server_name',$this->GetHost()); + } + // + // Note that even if SNI fails, the socket will still open, but the + // web server should send a 400 error. + // + return (stream_socket_client($this->GetPrefix() . $s_ip . ":" . $this->GetPort(), + $errno,$errstr,$i_timeout,STREAM_CLIENT_CONNECT,$context)); + } + + /** @noinspection PhpUndefinedVariableInspection */ + function Open() + { + $this->ClearError(); + if (!isset($this->_sHost) || !isset($this->_iPort)) { + return ($this->_SetError($this->nErrInit)); + } + if (!$this->Resolve()) { + return (FALSE); + } + FMDebug("Starting socket open"); + $f_sock = FALSE; + // + // Now, run through the list of IPs until we find one that connects. + // However, this can cause problems with SNI in SSL/TLS connections. + // If there is only one IP address, use the host name. + // Otherwise, if we can specify SNI and it's an SSL connection + // use streams, otherwise try each IP individually. + // + if (count($this->_aIPs) == 1) { + FMDebug("Trying host " . $this->_sHost . ", timeout " . $this->GetConnectionTimeout()); + $f_sock = @fsockopen($this->GetPrefix() . $this->_sHost,$this->GetPort(), + $errno,$errstr,$this->GetConnectionTimeout()); + } else { + foreach ($this->_aIPs as $s_ip) { + global $ExecEnv; + + FMDebug("Trying IP $s_ip, timeout " . $this->GetConnectionTimeout()); + if ($ExecEnv->IsPHPAtLeast("5.3.2") && substr($this->GetPrefix(),0,3) == "ssl") { + if (($f_sock = $this->_SSLOpen($s_ip,$errno,$errstr, + $this->GetConnectionTimeout())) !== FALSE + ) { + break; + } + } elseif (($f_sock = @fsockopen($this->GetPrefix() . $s_ip,$this->GetPort(), + $errno,$errstr,$this->GetConnectionTimeout())) !== FALSE + ) { + break; + } + } + } + if ($f_sock === FALSE) { + FMDebug("open failed: $errno $errstr"); + return ($this->_SetError($this->nErrSocket,$errno,$errstr)); + } + $this->_fSock = $f_sock; + FMDebug("Done socket open"); + return (TRUE); + } + + function Read() + { + $this->ClearError(); + $a_lines = array(); + while (($s_line = fgets($this->_fSock)) !== FALSE) { + $a_lines[] = $s_line; + } + FMDebug("Read " . count($a_lines) . " lines"); + return ($a_lines); + } + + function Write($s_str,$b_flush = TRUE) + { + $this->ClearError(); + if (!isset($this->_fSock)) { + return ($this->_SetError($this->nErrInit)); + } + if (($n_write = fwrite($this->_fSock,$s_str)) === FALSE) { + return ($this->_SetError($this->nErrWrite)); + } + if ($n_write != strlen($s_str)) { + return ($this->_SetError($this->nErrWriteShort)); + } + if ($b_flush) { + if (fflush($this->_fSock) === FALSE) { + return ($this->_SetError($this->nErrWriteShort)); + } + } + return (TRUE); + } + + function Close() + { + if (isset($this->_fSock)) { + fclose($this->_fSock); + unset($this->_fSock); + } + } +} + +/* + * Class: HTTPGet + * Description: + * A class that implements HTTP GET method. + */ + +class HTTPGet extends NetIO +{ + var $_sURL; + var $_aURLSplit; + + var $_sRequest; + var $_aResponse; + var $_aRespHeaders; + + var $_sAuthLine; + var $_sAuthType; + var $_sAuthUser; + var $_sAuthPass; + + var $_sAgent; + + var $nErrParse = -1000; // failed to parse URL + var $nErrScheme = -1001; // unsupported URL scheme + + function __construct($s_url = "") + { + parent::__construct(); + $this->_aURLSplit = array(); + if (($this->_sURL = $s_url) !== "") { + $this->_SplitURL(); + } + } + + function _SplitURL() + { + FMDebug("URL: " . $this->_sURL); + if (($this->_aURLSplit = parse_url($this->_sURL)) === FALSE) { + $this->_aURLSplit = array(); + return ($this->_SetError($this->nErrParse)); + } + return (TRUE); + } + + function GetURLSplit() + { + return ($this->_aURLSplit); + } + + function SetURL($s_url) + { + $this->_aURLSplit = array(); + $this->_sURL = $s_url; + return ($this->_SplitURL()); + } + + function _Init() + { + if (!isset($this->_aURLSplit["host"])) { + return ($this->_SetError($this->nErrInit)); + } + $this->SetHost($this->_aURLSplit["host"]); + $i_port = 80; + $b_use_ssl = false; + if (isset($this->_aURLSplit["scheme"])) { + switch (strtolower($this->_aURLSplit["scheme"])) { + case "http": + break; + case "https": + $b_use_ssl = true; + $i_port = 443; + break; + default: + return ($this->_SetError($this->nErrScheme)); + } + } + if (isset($this->_aURLSplit["port"])) { + $i_port = $this->_aURLSplit["port"]; + } + if ($b_use_ssl) + // + // we require ssl:// for port 443 + // + { + $this->SetPrefix("ssl://"); + } + $this->SetPort($i_port); + return (TRUE); + } + + function _SendRequest() + { + $this->_PrepareRequest(); + return (parent::Write($this->_sRequest)); + } + + function _PrepareRequest($s_method = 'GET') + { + FMDebug("Path: " . $this->_aURLSplit["path"]); + if (!isset($this->_aURLSplit["path"]) || $this->_aURLSplit["path"] === "") { + $s_path = "/"; + } // default path + else { + $s_path = $this->_aURLSplit["path"]; + } + if (isset($this->_aURLSplit["query"])) { + // + // add the query to the path + // Note that parse_url decodes the query string (urldecode), so + // we need to split it into its component parameters + // are re-encode their values. Calling urlencode($this->_aURLSplit["query"]) + // encodes the '=' between parameters and this breaks things. + // + $a_params = explode('&',$this->_aURLSplit["query"]); + foreach ($a_params as $i_idx => $s_param) { + if (($i_pos = strpos($s_param,"=")) === false) { + $a_params[$i_idx] = urlencode($s_param); + } else { + $a_params[$i_idx] = substr($s_param,0,$i_pos) . '=' . + urlencode(substr($s_param,$i_pos + 1)); + } + } + $s_path .= "?" . implode('&',$a_params); + } + // + // add the fragment to the path. + // + if (isset($this->_aURLSplit["fragment"])) { + $s_path .= '#' . urlencode($this->_aURLSplit["fragment"]); + } + // + // build the request + // + $s_req = $s_method . " $s_path HTTP/1.0\r\n"; + // + // Add authentication + // + if (isset($this->_sAuthLine)) { + $s_req .= "Authorization: $this->_sAuthLine\r\n"; + } elseif (isset($this->_sAuthType)) { + $s_req .= "Authorization: " . $this->_sAuthType . " " . + base64_encode($this->_sAuthUser . ":" . $this->_sAuthPass) . "\r\n"; + } + // + // Specify the host name + // + $s_req .= "Host: " . $this->GetHost() . "\r\n"; + // + // Specify the user agent + // + if (isset($this->_sAgent)) { + $s_req .= "User-Agent: " . $this->_sAgent . "\r\n"; + } + // + // Accept any output + // use of concatenation to avoid problems with IDE syntax highlighting. + // + $s_req .= "Accept: */" . "*\r\n"; + $s_req .= $this->_AdditionalHeaders(); + // + // End of request headers + // + $s_req .= "\r\n"; + $this->_sRequest = $s_req; + } + + function _AdditionalHeaders() + { + return (''); + } + + function _GetResponse() + { + FMDebug("Reading"); + if (($a_lines = parent::Read()) === FALSE) { + return (FALSE); + } + + $this->_aRespHeaders = $this->_aResponse = array(); + $b_body = FALSE; + for ($ii = 0 ; $ii < count($a_lines) ; $ii++) { + if ($b_body) { + //FMDebug("Body line: ".rtrim($a_lines[$ii])); + $this->_aResponse[] = $a_lines[$ii]; + } elseif ($a_lines[$ii] == "\r\n" || $a_lines[$ii] == "\n") { + $b_body = TRUE; + } else { + //FMDebug("Header line: ".rtrim($a_lines[$ii])); + $this->_aRespHeaders[] = $a_lines[$ii]; + } + } + return (TRUE); + } + + function GetResponseHeaders() + { + return ($this->_aRespHeaders); + } + + function FindHeader($s_name) + { + $s_name = strtolower($s_name); + $i_len = strlen($s_name); + for ($ii = 0 ; $ii < count($this->_aRespHeaders) ; $ii++) { + $s_line = $this->_aRespHeaders[$ii]; + if (($s_hdr = substr($s_line,0,$i_len)) !== false) { + $s_hdr = strtolower($s_hdr); + if ($s_hdr === $s_name && substr($s_line,$i_len,1) === ":") { + return (trim(substr($s_line,$i_len + 1))); + } + } + } + return (false); + } + + function GetHTTPStatus() + { + $i_http_code = 0; + $s_status = ""; + for ($ii = 0 ; $ii < count($this->_aRespHeaders) ; $ii++) { + $s_line = $this->_aRespHeaders[$ii]; + if (substr($s_line,0,4) == "HTTP") { + $i_pos = strpos($s_line," "); + $s_status = substr($s_line,$i_pos + 1); + $i_end_pos = strpos($s_status," "); + if ($i_end_pos === false) { + $i_end_pos = strlen($s_status); + } + $i_http_code = (int)substr($s_status,0,$i_end_pos); + } + } + return (array($i_http_code,$s_status)); + } + + function Resolve() + { + if (!$this->_Init()) { + return (FALSE); + } + return (parent::Resolve()); + } + + function Read() + { + if (!$this->_Init()) { + return (FALSE); + } + FMDebug("Init done"); + if (!$this->Open()) { + return (FALSE); + } + FMDebug("Open done"); + if (!$this->_SendRequest()) { + return (FALSE); + } + FMDebug("Send done"); + if (!$this->_GetResponse()) { + return (FALSE); + } + FMDebug("Get done"); + $this->Close(); + return ($this->_aResponse); + } + + function SetAuthenticationLine($s_auth) + { + $this->_sAuthLine = $s_auth; + } + + function SetAuthentication($s_type,$s_user,$s_pass) + { + $this->_sAuthType = $s_type; + $this->_sAuthUser = $s_user; + $this->_sAuthPass = $s_pass; + } + + function SetAgent($s_agent) + { + $this->_sAgent = $s_agent; + } +} + +/* + * Class: HTTPPost + * Description: + * A class that implements HTTP POST method. + */ + +class HTTPPost extends HTTPGet +{ + var $_sPostData; /* data to POST */ + + function __construct($s_url = "") + { + $this->_sPostData = ''; + parent::__construct($s_url); + } + + function _SendRequest() + { + $this->_PrepareRequest(); + return (NetIO::Write($this->_sRequest)); + } + + function _PrepareRequest($s_method = 'POST') + { + parent::_PrepareRequest($s_method); + $this->_AddData(); + } + + function _AdditionalHeaders() + { + // + // we don't handle file uploads yet + // + $a_hdrs = array( + 'Content-Type: application/x-www-form-urlencoded', + 'Content-Length: ' . strlen($this->_sPostData), + ); + return (implode("\r\n",$a_hdrs)); + } + + function _AddData() + { + $this->_sRequest .= "\r\n"; // blank line after headers + $this->_sRequest .= $this->_sPostData; + } + + function _EncodeData($a_fields) + { + $s_data = ''; + foreach ($a_fields as $s_name => $s_value) { + if ($s_data != '') { + $s_data .= '&'; + } + if (is_string($s_value)) { + $s_data .= urlencode($s_name) . '=' . urlencode($s_value); + } else { + $s_data .= urlencode($s_name) . '=' . urlencode(serialize($s_value)); + } + } + return ($s_data); + } + + function Post($a_fields) + { + // + // we don't handle file uploads yet + // + $this->_sPostData = $this->_EncodeData($a_fields); + return ($this->Read()); + } +} + +// +// Load a template file into a string. +// +function LoadTemplate($s_name,$s_dir,$s_url,$b_ret_lines = false) +{ + global $php_errormsg; + + $s_buf = ""; + $a_lines = array(); + if (!empty($s_dir)) { + $s_name = "$s_dir/" . basename($s_name); + @ $fp = fopen($s_name,"r"); + if ($fp === false) { + SendAlert(GetMessage(MSG_OPEN_TEMPLATE,array("NAME" => $s_name, + "ERROR" => CheckString($php_errormsg) + ))); + return (false); + } + if ($b_ret_lines) { + $a_lines = ReadLines($fp); + } else + // + // load the whole template into a string + // + { + $s_buf = fread($fp,filesize($s_name)); + } + fclose($fp); + } else { + if (substr($s_url,-1) == '/') { + $s_name = "$s_url" . basename($s_name); + } else { + $s_name = "$s_url/" . basename($s_name); + } + if (($m_data = GetURL($s_name,$s_error,$b_ret_lines)) === false) { + SendAlert($s_error); + return (false); + } + if ($b_ret_lines) { + $a_lines = $m_data; + // + // strip line terminations from each line + // + for ($ii = count($a_lines) ; --$ii >= 0 ;) { + $s_line = $a_lines[$ii]; + $s_line = str_replace("\r","",$s_line); + $s_line = str_replace("\n","",$s_line); + $a_lines[$ii] = $s_line; + } + } else { + $s_buf = $m_data; + } + } + return ($b_ret_lines ? $a_lines : $s_buf); +} + +// +// To show an error template. The template must be HTML and, for security +// reasons, must be a file on the server in the directory specified +// by $TEMPLATEDIR or $TEMPLATEURL. +// $a_specs is an array of substitutions to perform, as follows: +// tag-name replacement string +// +// For example: +// "fmerror"=>"An error message" +// +function ShowErrorTemplate($s_name,$a_specs,$b_user_error) +{ + if (function_exists('FMHookShowErrorTemplate')) { + if (FMHookShowErrorTemplate($s_name,$a_specs,$b_user_error)) { + return (true); + } + } + if (Settings::isEmpty('TEMPLATEDIR') && Settings::isEmpty('TEMPLATEURL')) { + SendAlert(GetMessage(MSG_TEMPLATES)); + return (false); + } + if (($s_buf = LoadTemplate($s_name,Settings::get('TEMPLATEDIR'),Settings::get('TEMPLATEURL'))) === false) { + return (false); + } + + // + // now look for the tags to replace + // + foreach ($a_specs as $s_tag => $s_value) + // + // search for + //\n"; + echo GetMessage(MSG_ABOUT_FORMMAIL,array("FM_VERS" => $FM_VERS, + "TECTITE" => "www.tectite.com" + )); + echo "
\n"; + } + echo "\n"; + echo "\n"; + } +} + +function GetMagicQuotesGPC() +{ + global $ExecEnv; + $b_result = false; + + // the magic_quotes_gpc setting was removed in PHP 5.4.0 + // get_magic_quotes_gpc was deprecated in PHP 7.4.0 and removed in PHP 8.0.0 + if (function_exists('get_magic_quotes_gpc')) { + if (!$ExecEnv->IsPHPAtLeast("5.4.0")) { + $b_result = (get_magic_quotes_gpc() != 0); + } + } + return $b_result; +} + +// +// Strip slashes if magic_quotes_gpc is set. +// +function StripGPC($s_value) +{ + global $ExecEnv; + + if (GetMagicQuotesGPC()) { + $s_value = stripslashes($s_value); + } + return ($s_value); +} + +// +// return an array, stripped of slashes if magic_quotes_gpc is set +// +function StripGPCArray($a_values) +{ + global $ExecEnv; + + if (GetMagicQuotesGPC()) { + foreach ($a_values as $m_key => $m_value) { + if (is_array($m_value)) + // + // strip arrays recursively + // + { + $a_values[$m_key] = StripGPCArray($m_value); + } else + // + // convert scalar to string and strip + // + { + $a_values[$m_key] = stripslashes("$m_value"); + } + } + } + + return ($a_values); +} + +// +// Strip a value of unwanted characters, which might be hacks. +// The stripping of \r and \n is a *critical* security feature. +// +function Strip($value) +{ + // + // When working with character sets such as UTF-8, stripping + // control characters is a *really bad idea* and breaks things. + // From version 8.22, FormMail only strips \r and \n as these + // are really the only characters that can cause header hacks + // to be inserted. (Strip means replace with a single space). + // We also handle multiple spaces. + // + $value = preg_replace('/[ \r\n]+/'," ",$value); // zap all CRLF and multiple blanks + return ($value); +} + +// +// Clean a value. This means: +// 1. convert to string +// 2. truncate to maximum length +// 3. strip the value of unwanted or dangerous characters (hacks) +// 4. trim both ends of whitespace +// Each element of an array is cleaned as above. This process occurs +// recursively, so arrays of arrays work OK too (though there's no +// need for that in this program). +// +// Non-scalar values are changed to the string "