From 1a2f789209c33bdede04e7ea7575b79c1f9063be Mon Sep 17 00:00:00 2001 From: Deltacms Date: Sun, 1 May 2022 11:45:17 +0200 Subject: [PATCH] modifications 4105 --- CHANGES.md | 7 +- README.md | 2 +- core/class/helper.class.php | 12 +- core/class/jsondb/Dot.class.php | 9 +- core/class/phpmailer/Exception.class.php | 5 +- core/class/phpmailer/PHPMailer.class.php | 812 ++++++++++++------ core/class/phpmailer/SMTP.class.php | 235 +++-- core/class/phpmailer/phpmailer.lang-fr.php | 38 + core/class/template.class.php | 17 +- core/core.js.php | 21 +- core/core.php | 67 +- core/include/update.inc.php | 4 + core/layout/common.css | 5 + core/layout/main.php | 24 +- core/module/config/config.php | 121 +-- core/module/config/view/restore/restore.php | 56 -- core/module/install/ressource/defaultdata.php | 5 +- core/module/page/page.php | 2 +- core/module/page/view/edit/edit.js.php | 7 +- core/module/user/user.php | 6 +- core/vendor/filemanager/config/config.php | 20 +- module/blog/blog.php | 18 +- module/blog/view/article/article.php | 30 +- module/blog/view/index/index.php | 23 +- module/form/form.php | 225 +++-- module/form/ressource/.htaccess | 4 + module/form/view/config/config.php | 21 +- module/form/view/index/index.css | 39 + module/form/view/index/index.js.php | 3 + module/form/view/index/index.php | 37 +- module/gallery/gallery.php | 2 +- module/gallery/view/edit/edit.js.php | 4 - module/statislite/include/stat.php | 4 +- module/statislite/statislite.php | 40 +- 34 files changed, 1211 insertions(+), 714 deletions(-) create mode 100644 core/class/phpmailer/phpmailer.lang-fr.php create mode 100644 module/form/ressource/.htaccess create mode 100644 module/form/view/index/index.css diff --git a/CHANGES.md b/CHANGES.md index f5cd8a0..c2c9e63 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ # Changelog +## Version 4.1.05 de Deltacms +- Modifications : + - Langues : RFM bilingue anglais / français et quelques compléments de traduction, + - Formulaire : avec le module Form possibilité de placer une pièce jointe dans le mail (jpg, jpeg, png ou gif) + ## Version 4.1.04 de Deltacms - Modifications : - Langues : ajout de 4 langues régionales, corse, breton, catalan, basque. @@ -9,7 +14,7 @@ - Statislite : amèioration de l'affichage de la date initiale, - Agenda : si la langue originale du site n'est pas reconnue, la langue d'administration est utilisée, - Blog : dans les labels de Tinymce si la langue originale du site n'est pas reconnue, la langue d'administration est utilisée, - - Langues : si le dapeau correspondant au langage du site n'existe pas un drapeau paer défaut est affiché dans les pages de localisation. + - Langues : si le dapeau correspondant au langage du site n'existe pas un drapeau par défaut est affiché dans les pages de localisation. - Correction : - Statislite : modification de l'initialisation du filtrage primaire. diff --git a/README.md b/README.md index 6874cdc..902ac88 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# DeltaCMS 4.1.04 +# DeltaCMS 4.1.05 DeltaCMS est un CMS sans base de données (flat-file) qui permet de créer et gérer facilement un site web sans aucune connaissance en programmation. L'administration du site est bilingue anglais ou français, le site peut être rédigé dans une des principales langues européennes. diff --git a/core/class/helper.class.php b/core/class/helper.class.php index ad71ddc..42472ac 100644 --- a/core/class/helper.class.php +++ b/core/class/helper.class.php @@ -321,7 +321,11 @@ class helper { * @return string */ public static function filter($text, $filter) { - $text = trim($text); + if( isset($text)){ + $text = trim( $text); + } else { + $text = ''; + } switch($filter) { case self::FILTER_BOOLEAN: $text = (bool) $text; @@ -367,10 +371,12 @@ class helper { $text = password_hash($text, PASSWORD_BCRYPT); break; case self::FILTER_STRING_LONG: - $text = mb_substr(filter_var($text, FILTER_SANITIZE_STRING), 0, 500000); + // $text = mb_substr(filter_var($text, FILTER_SANITIZE_STRING), 0, 500000); + $text = mb_substr( strip_tags($text) , 0, 500000); break; case self::FILTER_STRING_SHORT: - $text = mb_substr(filter_var($text, FILTER_SANITIZE_STRING), 0, 500); + // $text = mb_substr(filter_var($text, FILTER_SANITIZE_STRING), 0, 500); + $text = mb_substr( strip_tags($text) , 0, 500); break; case self::FILTER_TIMESTAMP: $text = date('Y-m-d H:i:s', $text); diff --git a/core/class/jsondb/Dot.class.php b/core/class/jsondb/Dot.class.php index 3c4af64..337352c 100644 --- a/core/class/jsondb/Dot.class.php +++ b/core/class/jsondb/Dot.class.php @@ -12,8 +12,6 @@ use ArrayAccess; */ class Dot implements ArrayAccess { - - /** @var array Data */ protected $data = []; /** @@ -271,21 +269,22 @@ class Dot implements ArrayAccess /** * ArrayAccess abstract methods */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { $this->set($offset, $value); } - + #[\ReturnTypeWillChange] public function offsetExists($offset) { return $this->has($offset); } - + #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->get($offset); } - + #[\ReturnTypeWillChange] public function offsetUnset($offset) { $this->delete($offset); diff --git a/core/class/phpmailer/Exception.class.php b/core/class/phpmailer/Exception.class.php index b1e552f..52eaf95 100644 --- a/core/class/phpmailer/Exception.class.php +++ b/core/class/phpmailer/Exception.class.php @@ -1,4 +1,5 @@ * @author Andy Prevost (codeworxtech) * @author Brent R. Matzelle (original founder) - * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2012 - 2020 Marcus Bointon * @copyright 2010 - 2012 Jim Jagielski * @copyright 2004 - 2009 Andy Prevost * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License @@ -34,6 +35,6 @@ class Exception extends \Exception */ public function errorMessage() { - return '' . htmlspecialchars($this->getMessage()) . "
\n"; + return '' . htmlspecialchars($this->getMessage(), ENT_COMPAT | ENT_HTML401) . "
\n"; } } diff --git a/core/class/phpmailer/PHPMailer.class.php b/core/class/phpmailer/PHPMailer.class.php index 51dff92..718216b 100644 --- a/core/class/phpmailer/PHPMailer.class.php +++ b/core/class/phpmailer/PHPMailer.class.php @@ -1,4 +1,5 @@ * @author Andy Prevost (codeworxtech) * @author Brent R. Matzelle (original founder) - * @copyright 2012 - 2019 Marcus Bointon + * @copyright 2012 - 2020 Marcus Bointon * @copyright 2010 - 2012 Jim Jagielski * @copyright 2004 - 2009 Andy Prevost * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License @@ -102,14 +103,14 @@ class PHPMailer * * @var string */ - public $From = 'root@localhost'; + public $From = ''; /** * The From name of the message. * * @var string */ - public $FromName = 'Root User'; + public $FromName = ''; /** * The envelope sender of the message. @@ -357,9 +358,9 @@ class PHPMailer public $AuthType = ''; /** - * An instance of the PHPMailer OAuth class. + * An implementation of the PHPMailer OAuthTokenProvider interface. * - * @var OAuth + * @var OAuthTokenProvider */ protected $oauth; @@ -388,11 +389,11 @@ class PHPMailer * SMTP class debug output mode. * Debug output level. * Options: - * * SMTP::DEBUG_OFF: No output - * * SMTP::DEBUG_CLIENT: Client messages - * * SMTP::DEBUG_SERVER: Client and server messages - * * SMTP::DEBUG_CONNECTION: As SERVER plus connection status - * * SMTP::DEBUG_LOWLEVEL: Noisy, low-level data output, rarely needed + * @see SMTP::DEBUG_OFF: No output + * @see SMTP::DEBUG_CLIENT: Client messages + * @see SMTP::DEBUG_SERVER: Client and server messages + * @see SMTP::DEBUG_CONNECTION: As SERVER plus connection status + * @see SMTP::DEBUG_LOWLEVEL: Noisy, low-level data output, rarely needed * * @see SMTP::$do_debug * @@ -427,9 +428,11 @@ class PHPMailer public $Debugoutput = 'echo'; /** - * Whether to keep SMTP connection open after each message. - * If this is set to true then to close the connection - * requires an explicit call to smtpClose(). + * Whether to keep the SMTP connection open after each message. + * If this is set to true then the connection will remain open after a send, + * and closing the connection will require an explicit call to smtpClose(). + * It's a good idea to use this if you are sending multiple messages as it reduces overhead. + * See the mailing list example for how to use it. * * @var bool */ @@ -441,6 +444,8 @@ class PHPMailer * Only supported in `mail` and `sendmail` transports, not in SMTP. * * @var bool + * + * @deprecated 6.0.0 PHPMailer isn't a mailing list manager! */ public $SingleTo = false; @@ -684,7 +689,7 @@ class PHPMailer protected $boundary = []; /** - * The array of available languages. + * The array of available text strings for the current language. * * @var array */ @@ -745,7 +750,7 @@ class PHPMailer * * @var string */ - const VERSION = '6.1.5'; + const VERSION = '6.6.0'; /** * Error severity: message only, continue processing. @@ -859,18 +864,25 @@ class PHPMailer $subject = $this->encodeHeader($this->secureHeader($subject)); } //Calling mail() with null params breaks + $this->edebug('Sending with mail()'); + $this->edebug('Sendmail path: ' . ini_get('sendmail_path')); + $this->edebug("Envelope sender: {$this->Sender}"); + $this->edebug("To: {$to}"); + $this->edebug("Subject: {$subject}"); + $this->edebug("Headers: {$header}"); if (!$this->UseSendmailOptions || null === $params) { $result = @mail($to, $subject, $body, $header); } else { + $this->edebug("Additional params: {$params}"); $result = @mail($to, $subject, $body, $header, $params); } - + $this->edebug('Result: ' . ($result ? 'true' : 'false')); return $result; } /** - * Output debugging info via user-defined method. - * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug). + * Output debugging info via a user-defined method. + * Only generates output if debug output is enabled. * * @see PHPMailer::$Debugoutput * @see PHPMailer::$SMTPDebug @@ -897,6 +909,7 @@ class PHPMailer switch ($this->Debugoutput) { case 'error_log': //Don't output, just log + /** @noinspection ForgottenDebugOutputInspection */ error_log($str); break; case 'html': @@ -1066,7 +1079,7 @@ class PHPMailer $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim $pos = strrpos($address, '@'); if (false === $pos) { - // At-sign is missing. + //At-sign is missing. $error_message = sprintf( '%s (%s): %s', $this->lang('invalid_address'), @@ -1082,7 +1095,7 @@ class PHPMailer return false; } $params = [$kind, $address, $name]; - // Enqueue addresses with IDN until we know the PHPMailer::$CharSet. + //Enqueue addresses with IDN until we know the PHPMailer::$CharSet. if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) { if ('Reply-To' !== $kind) { if (!array_key_exists($address, $this->RecipientsQueue)) { @@ -1099,7 +1112,7 @@ class PHPMailer return false; } - // Immediately add standard addresses without IDN. + //Immediately add standard addresses without IDN. return call_user_func_array([$this, 'addAnAddress'], $params); } @@ -1172,19 +1185,39 @@ class PHPMailer * * @param string $addrstr The address list string * @param bool $useimap Whether to use the IMAP extension to parse the list + * @param string $charset The charset to use when decoding the address list string. * * @return array */ - public static function parseAddresses($addrstr, $useimap = true) + public static function parseAddresses($addrstr, $useimap = true, $charset = self::CHARSET_ISO88591) { $addresses = []; if ($useimap && function_exists('imap_rfc822_parse_adrlist')) { //Use this built-in parser if it's available $list = imap_rfc822_parse_adrlist($addrstr, ''); + // Clear any potential IMAP errors to get rid of notices being thrown at end of script. + imap_errors(); foreach ($list as $address) { - if (('.SYNTAX-ERROR.' !== $address->host) && static::validateAddress( - $address->mailbox . '@' . $address->host - )) { + if ( + '.SYNTAX-ERROR.' !== $address->host && + static::validateAddress($address->mailbox . '@' . $address->host) + ) { + //Decode the name part if it's present and encoded + if ( + property_exists($address, 'personal') && + //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled + defined('MB_CASE_UPPER') && + preg_match('/^=\?.*\?=$/s', $address->personal) + ) { + $origCharset = mb_internal_encoding(); + mb_internal_encoding($charset); + //Undo any RFC2047-encoded spaces-as-underscores + $address->personal = str_replace('_', '=20', $address->personal); + //Decode the name + $address->personal = mb_decode_mimeheader($address->personal); + mb_internal_encoding($origCharset); + } + $addresses[] = [ 'name' => (property_exists($address, 'personal') ? $address->personal : ''), 'address' => $address->mailbox . '@' . $address->host, @@ -1208,9 +1241,22 @@ class PHPMailer } else { list($name, $email) = explode('<', $address); $email = trim(str_replace('>', '', $email)); + $name = trim($name); if (static::validateAddress($email)) { + //Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled + //If this name is encoded, decode it + if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) { + $origCharset = mb_internal_encoding(); + mb_internal_encoding($charset); + //Undo any RFC2047-encoded spaces-as-underscores + $name = str_replace('_', '=20', $name); + //Decode the name + $name = mb_decode_mimeheader($name); + mb_internal_encoding($origCharset); + } $addresses[] = [ - 'name' => trim(str_replace(['"', "'"], '', $name)), + //Remove any surrounding quotes and spaces from the name + 'name' => trim($name, '\'" '), 'address' => $email, ]; } @@ -1236,9 +1282,10 @@ class PHPMailer { $address = trim($address); $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim - // Don't validate now addresses with IDN. Will be done in send(). + //Don't validate now addresses with IDN. Will be done in send(). $pos = strrpos($address, '@'); - if ((false === $pos) + if ( + (false === $pos) || ((!$this->has8bitChars(substr($address, ++$pos)) || !static::idnSupported()) && !static::validateAddress($address)) ) { @@ -1306,8 +1353,9 @@ class PHPMailer if (null === $patternselect) { $patternselect = static::$validator; } - if (is_callable($patternselect)) { - return $patternselect($address); + //Don't allow strings as callables, see SECURITY.md and CVE-2021-3603 + if (is_callable($patternselect) && !is_string($patternselect)) { + return call_user_func($patternselect, $address); } //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 if (strpos($address, "\n") !== false || strpos($address, "\r") !== false) { @@ -1348,7 +1396,7 @@ class PHPMailer /* * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. * - * @see http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) + * @see https://html.spec.whatwg.org/#e-mail-state-(type=email) */ return (bool) preg_match( '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . @@ -1388,23 +1436,33 @@ class PHPMailer */ public function punyencodeAddress($address) { - // Verify we have required functions, CharSet, and at-sign. + //Verify we have required functions, CharSet, and at-sign. $pos = strrpos($address, '@'); - if (!empty($this->CharSet) && + if ( + !empty($this->CharSet) && false !== $pos && static::idnSupported() ) { $domain = substr($address, ++$pos); - // Verify CharSet string is a valid one, and domain properly encoded in this CharSet. + //Verify CharSet string is a valid one, and domain properly encoded in this CharSet. if ($this->has8bitChars($domain) && @mb_check_encoding($domain, $this->CharSet)) { - $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet); + //Convert the domain from whatever charset it's in to UTF-8 + $domain = mb_convert_encoding($domain, self::CHARSET_UTF8, $this->CharSet); //Ignore IDE complaints about this line - method signature changed in PHP 5.4 $errorcode = 0; if (defined('INTL_IDNA_VARIANT_UTS46')) { - $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_UTS46); + //Use the current punycode standard (appeared in PHP 7.2) + $punycode = idn_to_ascii( + $domain, + \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | + \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, + \INTL_IDNA_VARIANT_UTS46 + ); } elseif (defined('INTL_IDNA_VARIANT_2003')) { - $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_2003); + //Fall back to this old, deprecated/removed encoding + $punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003); } else { + //Fall back to a default we don't know about $punycode = idn_to_ascii($domain, $errorcode); } if (false !== $punycode) { @@ -1452,8 +1510,9 @@ class PHPMailer */ public function preSend() { - if ('smtp' === $this->Mailer - || ('mail' === $this->Mailer && stripos(PHP_OS, 'WIN') === 0) + if ( + 'smtp' === $this->Mailer + || ('mail' === $this->Mailer && (\PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0)) ) { //SMTP mandates RFC-compliant line endings //and it's also used with mail() on Windows @@ -1463,25 +1522,21 @@ class PHPMailer static::setLE(PHP_EOL); } //Check for buggy PHP versions that add a header with an incorrect line break - if ('mail' === $this->Mailer - && ((PHP_VERSION_ID >= 70000 && PHP_VERSION_ID < 70017) - || (PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70103)) + if ( + 'mail' === $this->Mailer + && ((\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70017) + || (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70103)) && ini_get('mail.add_x_header') === '1' && stripos(PHP_OS, 'WIN') === 0 ) { - trigger_error( - 'Your version of PHP is affected by a bug that may result in corrupted messages.' . - ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' . - ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', - E_USER_WARNING - ); + trigger_error($this->lang('buggy_php'), E_USER_WARNING); } try { - $this->error_count = 0; // Reset errors + $this->error_count = 0; //Reset errors $this->mailHeader = ''; - // Dequeue recipient and Reply-To addresses with IDN + //Dequeue recipient and Reply-To addresses with IDN foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { $params[1] = $this->punyencodeAddress($params[1]); call_user_func_array([$this, 'addAnAddress'], $params); @@ -1490,7 +1545,7 @@ class PHPMailer throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL); } - // Validate From, Sender, and ConfirmReadingTo addresses + //Validate From, Sender, and ConfirmReadingTo addresses foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) { $this->$address_kind = trim($this->$address_kind); if (empty($this->$address_kind)) { @@ -1514,29 +1569,29 @@ class PHPMailer } } - // Set whether the message is multipart/alternative + //Set whether the message is multipart/alternative if ($this->alternativeExists()) { $this->ContentType = static::CONTENT_TYPE_MULTIPART_ALTERNATIVE; } $this->setMessageType(); - // Refuse to send an empty message unless we are specifically allowing it + //Refuse to send an empty message unless we are specifically allowing it if (!$this->AllowEmpty && empty($this->Body)) { throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); } //Trim subject consistently $this->Subject = trim($this->Subject); - // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) + //Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) $this->MIMEHeader = ''; $this->MIMEBody = $this->createBody(); - // createBody may have added some headers, so retain them + //createBody may have added some headers, so retain them $tempheaders = $this->MIMEHeader; $this->MIMEHeader = $this->createHeader(); $this->MIMEHeader .= $tempheaders; - // To capture the complete message when using mail(), create - // an extra header list which createHeader() doesn't fold in + //To capture the complete message when using mail(), create + //an extra header list which createHeader() doesn't fold in if ('mail' === $this->Mailer) { if (count($this->to) > 0) { $this->mailHeader .= $this->addrAppend('To', $this->to); @@ -1549,8 +1604,9 @@ class PHPMailer ); } - // Sign with DKIM if enabled - if (!empty($this->DKIM_domain) + //Sign with DKIM if enabled + if ( + !empty($this->DKIM_domain) && !empty($this->DKIM_selector) && (!empty($this->DKIM_private_string) || (!empty($this->DKIM_private) @@ -1589,7 +1645,7 @@ class PHPMailer public function postSend() { try { - // Choose the mailer and send through it + //Choose the mailer and send through it switch ($this->Mailer) { case 'sendmail': case 'qmail': @@ -1607,6 +1663,9 @@ class PHPMailer return $this->mailSend($this->MIMEHeader, $this->MIMEBody); } } catch (Exception $exc) { + if ($this->Mailer === 'smtp' && $this->SMTPKeepAlive == true) { + $this->smtp->reset(); + } $this->setError($exc->getMessage()); $this->edebug($exc->getMessage()); if ($this->exceptions) { @@ -1631,22 +1690,47 @@ class PHPMailer */ protected function sendmailSend($header, $body) { + if ($this->Mailer === 'qmail') { + $this->edebug('Sending with qmail'); + } else { + $this->edebug('Sending with sendmail'); + } $header = static::stripTrailingWSP($header) . static::$LE . static::$LE; + //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver + //A space after `-f` is optional, but there is a long history of its presence + //causing problems, so we don't use one + //Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html + //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html + //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html + //Example problem: https://www.drupal.org/node/1057954 - // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. - if (!empty($this->Sender) && self::isShellSafe($this->Sender)) { - if ('qmail' === $this->Mailer) { + //PHP 5.6 workaround + $sendmail_from_value = ini_get('sendmail_from'); + if (empty($this->Sender) && !empty($sendmail_from_value)) { + //PHP config has a sender address we can use + $this->Sender = ini_get('sendmail_from'); + } + //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) { + if ($this->Mailer === 'qmail') { $sendmailFmt = '%s -f%s'; } else { $sendmailFmt = '%s -oi -f%s -t'; } - } elseif ('qmail' === $this->Mailer) { - $sendmailFmt = '%s'; } else { + //allow sendmail to choose a default envelope sender. It may + //seem preferable to force it to use the From header as with + //SMTP, but that introduces new problems (see + //), and + //it has historically worked this way. $sendmailFmt = '%s -oi -t'; } $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); + $this->edebug('Sendmail path: ' . $this->Sendmail); + $this->edebug('Sendmail command: ' . $sendmail); + $this->edebug('Envelope sender: ' . $this->Sender); + $this->edebug("Headers: {$header}"); if ($this->SingleTo) { foreach ($this->SingleToArray as $toAddr) { @@ -1654,13 +1738,15 @@ class PHPMailer if (!$mail) { throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); } + $this->edebug("To: {$toAddr}"); fwrite($mail, 'To: ' . $toAddr . "\n"); fwrite($mail, $header); fwrite($mail, $body); $result = pclose($mail); + $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet); $this->doCallback( ($result === 0), - [$toAddr], + [[$addrinfo['address'], $addrinfo['name']]], $this->cc, $this->bcc, $this->Subject, @@ -1668,6 +1754,7 @@ class PHPMailer $this->From, [] ); + $this->edebug("Result: " . ($result === 0 ? 'true' : 'false')); if (0 !== $result) { throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); } @@ -1690,6 +1777,7 @@ class PHPMailer $this->From, [] ); + $this->edebug("Result: " . ($result === 0 ? 'true' : 'false')); if (0 !== $result) { throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); } @@ -1710,8 +1798,15 @@ class PHPMailer */ protected static function isShellSafe($string) { - // Future-proof - if (escapeshellcmd($string) !== $string + //It's not possible to use shell commands safely (which includes the mail() function) without escapeshellarg, + //but some hosting providers disable it, creating a security problem that we don't want to have to deal with, + //so we don't. + if (!function_exists('escapeshellarg') || !function_exists('escapeshellcmd')) { + return false; + } + + if ( + escapeshellcmd($string) !== $string || !in_array(escapeshellarg($string), ["'$string'", "\"$string\""]) ) { return false; @@ -1722,9 +1817,9 @@ class PHPMailer for ($i = 0; $i < $length; ++$i) { $c = $string[$i]; - // All other characters have a special meaning in at least one common shell, including = and +. - // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. - // Note that this does permit non-Latin alphanumeric characters based on the current locale. + //All other characters have a special meaning in at least one common shell, including = and +. + //Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. + //Note that this does permit non-Latin alphanumeric characters based on the current locale. if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { return false; } @@ -1744,7 +1839,28 @@ class PHPMailer */ protected static function isPermittedPath($path) { - return !preg_match('#^[a-z]+://#i', $path); + //Matches scheme definition from https://tools.ietf.org/html/rfc3986#section-3.1 + return !preg_match('#^[a-z][a-z\d+.-]*://#i', $path); + } + + /** + * Check whether a file path is safe, accessible, and readable. + * + * @param string $path A relative or absolute path to a file + * + * @return bool + */ + protected static function fileIsAccessible($path) + { + if (!static::isPermittedPath($path)) { + return false; + } + $readable = file_exists($path); + //If not a UNC path (expected to start with \\), check read permission, see #2069 + if (strpos($path, '\\\\') !== 0) { + $readable = $readable && is_readable($path); + } + return $readable; } /** @@ -1777,11 +1893,18 @@ class PHPMailer //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html //Example problem: https://www.drupal.org/node/1057954 - // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. - if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) { - $params = sprintf('-f%s', $this->Sender); + //CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + + //PHP 5.6 workaround + $sendmail_from_value = ini_get('sendmail_from'); + if (empty($this->Sender) && !empty($sendmail_from_value)) { + //PHP config has a sender address we can use + $this->Sender = ini_get('sendmail_from'); } if (!empty($this->Sender) && static::validateAddress($this->Sender)) { + if (self::isShellSafe($this->Sender)) { + $params = sprintf('-f%s', $this->Sender); + } $old_from = ini_get('sendmail_from'); ini_set('sendmail_from', $this->Sender); } @@ -1789,7 +1912,17 @@ class PHPMailer if ($this->SingleTo && count($toArr) > 1) { foreach ($toArr as $toAddr) { $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); - $this->doCallback($result, [$toAddr], $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + $addrinfo = static::parseAddresses($toAddr, true, $this->CharSet); + $this->doCallback( + $result, + [[$addrinfo['address'], $addrinfo['name']]], + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); } } else { $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); @@ -1867,7 +2000,7 @@ class PHPMailer } $callbacks = []; - // Attempt to send to all recipients + //Attempt to send to all recipients foreach ([$this->to, $this->cc, $this->bcc] as $togroup) { foreach ($togroup as $to) { if (!$this->smtp->recipient($to[0], $this->dsn)) { @@ -1878,11 +2011,11 @@ class PHPMailer $isSent = true; } - $callbacks[] = ['issent'=>$isSent, 'to'=>$to[0]]; + $callbacks[] = ['issent' => $isSent, 'to' => $to[0], 'name' => $to[1]]; } } - // Only send the DATA command if we have viable recipients + //Only send the DATA command if we have viable recipients if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) { throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL); } @@ -1899,7 +2032,7 @@ class PHPMailer foreach ($callbacks as $cb) { $this->doCallback( $cb['issent'], - [$cb['to']], + [[$cb['to'], $cb['name']]], [], [], $this->Subject, @@ -1944,7 +2077,7 @@ class PHPMailer $options = $this->SMTPOptions; } - // Already connected? + //Already connected? if ($this->smtp->connected()) { return true; } @@ -1958,20 +2091,22 @@ class PHPMailer foreach ($hosts as $hostentry) { $hostinfo = []; - if (!preg_match( - '/^(?:(ssl|tls):\/\/)?(.+?)(?::(\d+))?$/', - trim($hostentry), - $hostinfo - )) { + if ( + !preg_match( + '/^(?:(ssl|tls):\/\/)?(.+?)(?::(\d+))?$/', + trim($hostentry), + $hostinfo + ) + ) { $this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry)); - // Not a valid host entry + //Not a valid host entry continue; } - // $hostinfo[1]: optional ssl or tls prefix - // $hostinfo[2]: the hostname - // $hostinfo[3]: optional port number - // The host string prefix can temporarily override the current setting for SMTPSecure - // If it's not specified, the default value is used + //$hostinfo[1]: optional ssl or tls prefix + //$hostinfo[2]: the hostname + //$hostinfo[3]: optional port number + //The host string prefix can temporarily override the current setting for SMTPSecure + //If it's not specified, the default value is used //Check the host name is a valid name or IP address before trying to use it if (!static::isValidHost($hostinfo[2])) { @@ -1983,11 +2118,11 @@ class PHPMailer $tls = (static::ENCRYPTION_STARTTLS === $this->SMTPSecure); if ('ssl' === $hostinfo[1] || ('' === $hostinfo[1] && static::ENCRYPTION_SMTPS === $this->SMTPSecure)) { $prefix = 'ssl://'; - $tls = false; // Can't have SSL and TLS at the same time + $tls = false; //Can't have SSL and TLS at the same time $secure = static::ENCRYPTION_SMTPS; } elseif ('tls' === $hostinfo[1]) { $tls = true; - // tls doesn't use a prefix + //TLS doesn't use a prefix $secure = static::ENCRYPTION_STARTTLS; } //Do we need the OpenSSL extension? @@ -2000,7 +2135,12 @@ class PHPMailer } $host = $hostinfo[2]; $port = $this->Port; - if (array_key_exists(3, $hostinfo) && is_numeric($hostinfo[3]) && $hostinfo[3] > 0 && $hostinfo[3] < 65536) { + if ( + array_key_exists(3, $hostinfo) && + is_numeric($hostinfo[3]) && + $hostinfo[3] > 0 && + $hostinfo[3] < 65536 + ) { $port = (int) $hostinfo[3]; } if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { @@ -2012,26 +2152,29 @@ class PHPMailer } $this->smtp->hello($hello); //Automatically enable TLS encryption if: - // * it's not disabled - // * we have openssl extension - // * we are not already using SSL - // * the server offers STARTTLS + //* it's not disabled + //* we have openssl extension + //* we are not already using SSL + //* the server offers STARTTLS if ($this->SMTPAutoTLS && $sslext && 'ssl' !== $secure && $this->smtp->getServerExt('STARTTLS')) { $tls = true; } if ($tls) { if (!$this->smtp->startTLS()) { - throw new Exception($this->lang('connect_host')); + $message = $this->getSmtpErrorMessage('connect_host'); + throw new Exception($message); } - // We must resend EHLO after TLS negotiation + //We must resend EHLO after TLS negotiation $this->smtp->hello($hello); } - if ($this->SMTPAuth && !$this->smtp->authenticate( - $this->Username, - $this->Password, - $this->AuthType, - $this->oauth - )) { + if ( + $this->SMTPAuth && !$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->oauth + ) + ) { throw new Exception($this->lang('authenticate')); } @@ -2039,16 +2182,20 @@ class PHPMailer } catch (Exception $exc) { $lastexception = $exc; $this->edebug($exc->getMessage()); - // We must have connected, but then failed TLS or Auth, so close connection nicely + //We must have connected, but then failed TLS or Auth, so close connection nicely $this->smtp->quit(); } } } - // If we get here, all connection attempts have failed, so close connection hard + //If we get here, all connection attempts have failed, so close connection hard $this->smtp->close(); - // As we've caught all exceptions, just report whatever the last one was + //As we've caught all exceptions, just report whatever the last one was if ($this->exceptions && null !== $lastexception) { throw $lastexception; + } elseif ($this->exceptions) { + // no exception was thrown, likely $this->smtp->connect() failed + $message = $this->getSmtpErrorMessage('connect_host'); + throw new Exception($message); } return false; @@ -2067,17 +2214,19 @@ class PHPMailer /** * Set the language for error messages. - * Returns false if it cannot load the language file. * The default language is English. * * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr") + * Optionally, the language code can be enhanced with a 4-character + * script annotation and/or a 2-character country annotation. * @param string $lang_path Path to the language file directory, with trailing separator (slash) + * Do not set this from user input! * - * @return bool + * @return bool Returns true if the requested language was loaded, false otherwise. */ public function setLanguage($langcode = 'en', $lang_path = '') { - // Backwards compatibility for renamed language codes + //Backwards compatibility for renamed language codes $renamed_langcodes = [ 'br' => 'pt_br', 'cz' => 'cs', @@ -2089,58 +2238,109 @@ class PHPMailer 'am' => 'hy', ]; - if (isset($renamed_langcodes[$langcode])) { + if (array_key_exists($langcode, $renamed_langcodes)) { $langcode = $renamed_langcodes[$langcode]; } - // Define full set of translatable strings in English + //Define full set of translatable strings in English $PHPMAILER_LANG = [ 'authenticate' => 'SMTP Error: Could not authenticate.', + 'buggy_php' => 'Your version of PHP is affected by a bug that may result in corrupted messages.' . + ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' . + ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', 'data_not_accepted' => 'SMTP Error: data not accepted.', 'empty_message' => 'Message body empty', 'encoding' => 'Unknown encoding: ', 'execute' => 'Could not execute: ', + 'extension_missing' => 'Extension missing: ', 'file_access' => 'Could not access file: ', 'file_open' => 'File Error: Could not open file: ', 'from_failed' => 'The following From address failed: ', 'instantiate' => 'Could not instantiate mail function.', 'invalid_address' => 'Invalid address: ', + 'invalid_header' => 'Invalid header name or value', 'invalid_hostentry' => 'Invalid hostentry: ', 'invalid_host' => 'Invalid host: ', 'mailer_not_supported' => ' mailer is not supported.', 'provide_address' => 'You must provide at least one recipient email address.', 'recipients_failed' => 'SMTP Error: The following recipients failed: ', 'signing' => 'Signing Error: ', + 'smtp_code' => 'SMTP code: ', + 'smtp_code_ex' => 'Additional SMTP info: ', 'smtp_connect_failed' => 'SMTP connect() failed.', + 'smtp_detail' => 'Detail: ', 'smtp_error' => 'SMTP server error: ', 'variable_set' => 'Cannot set or reset variable: ', - 'extension_missing' => 'Extension missing: ', ]; if (empty($lang_path)) { - // Calculate an absolute path so it can work if CWD is not here + //Calculate an absolute path so it can work if CWD is not here $lang_path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR; } + //Validate $langcode - if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) { + $foundlang = true; + $langcode = strtolower($langcode); + if ( + !preg_match('/^(?P[a-z]{2})(?P - + + + @@ -64,9 +66,10 @@ if( $this->getInput('DELTA_I18N_SITE') !== '' && $this->getInput('DELTA_I18N_SIT } ?> - -
- + +
+ getData(['theme', 'menu', 'position']) === 'body-first' || $this->getData(['theme', 'menu', 'position']) === 'top' ): ?> @@ -217,10 +220,11 @@ if( $this->getInput('DELTA_I18N_SITE') !== '' && $this->getInput('DELTA_I18N_SIT getData(['theme', 'footer', 'position']) === 'site'? '
' : '';?> - -
-
- + + +
+
diff --git a/core/module/config/config.php b/core/module/config/config.php index d6a2c07..d6fb2e8 100644 --- a/core/module/config/config.php +++ b/core/module/config/config.php @@ -25,7 +25,6 @@ class config extends common { 'generateFiles' => self::GROUP_ADMIN, 'index' => self::GROUP_ADMIN, 'restore' => self::GROUP_ADMIN, - 'updateBaseUrl' => self::GROUP_ADMIN, 'script' => self::GROUP_ADMIN, 'logReset' => self::GROUP_ADMIN, 'logDownload'=> self::GROUP_ADMIN, @@ -405,62 +404,19 @@ class config extends common { $files [] = ( basename( $stat['name'] )); } - // Lire la dataversion - $tmpDir = uniqid(4); - $success = $zip->extractTo( self::TEMP_DIR . $tmpDir ); - $data = file_get_contents( self::TEMP_DIR . $tmpDir . '/data/core.json'); - $obj = json_decode($data); - $dataVersion = strval ($obj->core->dataVersion); - switch (strlen($dataVersion)) { - case 4: - if (substr($dataVersion,0,1) === '9' ) { - $version = 9; - } else { - $version = 0; - } - break; - case 5: - $version = substr($dataVersion,0,2); - break; - default: - $version = 0; - break; - } - $this->removeDir(self::TEMP_DIR . $tmpDir ); + // Option active, les users sont stockées + if ($this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true ) $users = $this->getData(['user']); - if ($version >= 10 ) { - // Option active, les users sont stockées - if ($this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true ) { - $users = $this->getData(['user']); - } - } elseif ($version === 0) { // Version invalide - // Valeurs en sortie erreur - $this->addOutput([ - 'title' => $text[0], - 'view' => 'restore', - 'notification' => $text[3], - 'state' => false - ]); - } - // Préserver les comptes des utilisateurs d'une version 9 si option cochée - // Positionnement d'une variable de session lue au constructeurs - if ($version === 9) { - $_SESSION['KEEP_USERS'] = $this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN); - } // Extraire le zip ou 'site/' $this->removeDir(self::DATA_DIR); $success = $zip->extractTo( 'site/' ); // Fermer l'archive $zip->close(); - // Restaurer les users originaux d'une v10 si option cochée - if (!empty($users) && - $version >= 10 && - $this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true) { - $this->setData(['user',$users]); - } + if (!empty($users) && $this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true) $this->setData(['user',$users]); } + // Message de notification $notification = $success === true ? $text[4] : $text[5] ; $redirect = $this->getInput('configRestoreImportUser', helper::FILTER_BOOLEAN) === true ? helper::baseUrl() . 'config/restore' : helper::baseUrl() . 'user/login/'; @@ -757,75 +713,6 @@ class config extends common { ]); } - /** - * Met à jour les données de site avec l'adresse transmise - */ - public function updateBaseUrl () { - // Lexique - $text = []; - $val = $this->getData(['config', 'i18n', 'langAdmin']); - switch ($val) { - case 'fr' : - $text[0] = 'Restaurer'; - $text[1] = ' conversion'; - $text[2] = ' effectuée'; - $text[3] = 'Aucune conversion'; - break; - case 'en' : - $text[0] = 'Restore'; - $text[1] = ' conversion'; - $text[2] = ' performed'; - $text[3] = 'No conversion'; - break; - } - // Supprimer l'information de redirection - $old = str_replace('?','',$this->getData(['core', 'baseUrl'])); - $new = helper::baseUrl(false,false); - $c3 = 0; - $success = false ; - // Boucler sur les pages - foreach($this->getHierarchy(null,null,null) as $parentId => $childIds) { - $content = $this->getPage($parentId, self::$i18n); - $content = $titre . ' ' . $content ; - $replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ; - $replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ; - - if ($c1 > 0 || $c2 > 0) { - $success = true; - $this->setPage($parentId, $replace, self::$i18n); - $c3 += $c1 + $c2; - } - foreach($childIds as $childId) { - $content = $this->getPage($childId, self::$i18n); - $content = $titre . ' ' . $content ; - $replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ; - $replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ; - if ($c1 > 0 || $c2 > 0) { - $success = true; - $this->setPage($childId, $replace, self::$i18n); - $c3 += $c1 + $c2; - } - } - } - // Traiter les modules dont la redirection - $content = $this->getdata(['module']); - $replace = $this->recursive_array_replace('href="' . $old , 'href="'. $new, $content, $c1); - $replace = $this->recursive_array_replace('src="' . $old , 'src="'. $new, $replace, $c2); - if ($content !== $replace) { - $this->setdata(['module',$replace]); - $c3 += $c1 + $c2; - $success = true; - } - // Mettre à jour la base URl - $this->setData(['core','baseUrl',helper::baseUrl(true,false)]); - // Valeurs en sortie - $this->addOutput([ - 'title' => $text[0], - 'view' => 'restore', - 'notification' => $success ? $c3. $text[1] . ($c3 > 1 ? 's' : '') . $text[2] . ($c3 > 1 ? 's' : '') : $text[3], - 'state' => $success ? true : false - ]); - } /** * Vider le fichier de log diff --git a/core/module/config/view/restore/restore.php b/core/module/config/view/restore/restore.php index c1b907f..67d979b 100644 --- a/core/module/config/view/restore/restore.php +++ b/core/module/config/view/restore/restore.php @@ -10,13 +10,6 @@ switch ($val) { $text[3] = 'Sélectionnez une archive au format ZIP'; $text[4] = 'L\'archive a été déposée dans le gestionnaire de fichiers.'; $text[5] = 'Préserver les comptes des utilisateurs déjà installés'; - $text[6] = 'Conversion après la restauration'; - $text[7] = 'Conversion des URL des ressources multimédia entre deux sites aux arborescences différentes.'; - $text[8] = 'Pas de donnée dans la sauvegarde'; - $text[9] = 'Dossier de l\'archive'; - $text[10] = 'Le dossier de base du site est stockée dans la sauvegarde.'; - $text[11] = 'Dossier du site actuel'; - $text[12] = 'Convertir'; break; case 'en' : $text[0] = 'Return'; @@ -25,13 +18,6 @@ switch ($val) { $text[3] = 'Select an archive in ZIP format'; $text[4] = 'The archive has been dropped into the file manager.'; $text[5] = 'Preserve user accounts already installed'; - $text[6] = 'Convert after restore'; - $text[7] = 'Conversion of media URLs between two sites with different trees'; - $text[8] = 'No data in backup'; - $text[9] = 'Archive folder'; - $text[10] = 'The site\'s base folder is stored in the backup'; - $text[11] = 'Current site folder'; - $text[12] = 'Convert'; break; } ?> @@ -75,46 +61,4 @@ switch ($val) { -
-
-
-

-
-
- getData(['core', 'baseUrl'])) ) { - $baseUrlValue = $text[8]; - $buttonClass = 'disabled'; - } elseif ($this->getData(['core', 'baseUrl']) === '') { - $baseUrlValue = '/'; - $buttonClass = helper::baseUrl(false,false) !== $this->getData(['core', 'baseUrl']) ? '' : 'disabled'; - } else { - $baseUrlValue = str_replace('?','',$this->getData(['core', 'baseUrl'])); - $buttonClass = helper::baseUrl(false,false) !== $baseUrlValue ? '' : 'disabled'; - } - echo template::text('configRestoreBaseURLToConvert', [ - 'label' => $text[9] , - 'value' => $baseUrlValue, - 'readonly' => true, - 'help' => $text[10] - ]); ?> -
-
- $text[11], - 'value' => helper::baseUrl(false,false), - 'readonly' => true - ]); ?> -
-
- helper::baseUrl() . 'config/updateBaseUrl', - 'class' => $buttonClass, - 'value' => $text[12] - ]); ?> -
-
-
-
-
diff --git a/core/module/install/ressource/defaultdata.php b/core/module/install/ressource/defaultdata.php index d229c8f..5ac604a 100644 --- a/core/module/install/ressource/defaultdata.php +++ b/core/module/install/ressource/defaultdata.php @@ -70,7 +70,7 @@ class init extends common { ] ], 'core' => [ - 'dataVersion' => 4104, + 'dataVersion' => 4105, 'lastBackup' => 0, 'lastClearTmp' => 0, 'lastAutoUpdate' => 0, @@ -805,7 +805,8 @@ class init extends common { 'config' => [ 'feeds' => true, 'feedsLabel' => 'Syndication RSS', - 'itemsperPage' => 4 + 'itemsperPage' => 4, + 'versionData' => '6.0' ], 'texts' => [ 'NoComment' => 'Pas encore de commentaire', diff --git a/core/module/page/page.php b/core/module/page/page.php index e7c35c0..852bc62 100644 --- a/core/module/page/page.php +++ b/core/module/page/page.php @@ -207,7 +207,7 @@ class page extends common { 'group' => self::GROUP_VISITOR, 'targetBlank' => false, 'title' => $pageTitle, - 'shortTitle' => $pageTitle, + 'shortTitle' => '', 'block' => '12', 'barLeft' => '', 'barRight' => '', diff --git a/core/module/page/view/edit/edit.js.php b/core/module/page/view/edit/edit.js.php index e70d3d6..7a2ce82 100644 --- a/core/module/page/view/edit/edit.js.php +++ b/core/module/page/view/edit/edit.js.php @@ -526,7 +526,12 @@ pageTypeMenuDOM.on("change", function() { } }); - +/** + * Duplication du champ Title dans Short title + */ +$("#pageEditTitle").on("input", function() { + $("#pageEditShortTitle").val($(this).val()); +}); /** diff --git a/core/module/user/user.php b/core/module/user/user.php index 65abe2c..8749390 100644 --- a/core/module/user/user.php +++ b/core/module/user/user.php @@ -657,9 +657,9 @@ class user extends common { } } // Journalisation - $dataLog = mb_detect_encoding(strftime('%d/%m/%y',time()), 'UTF-8', true) - ? strftime('%d/%m/%y',time()) . ';' . strftime('%R',time()) . ';' - : utf8_encode(strftime('%d/%m/%y',time())) . ';' . utf8_encode(strftime('%R',time())) . ';' ; + $dataLog = mb_detect_encoding(date('d\/m\/y',time()), 'UTF-8', true) + ? date('d\/m\/y',time()) . ';' . date('H\:i',time()) . ';' + : utf8_encode(date('d\/m\/y',time())) . ';' . utf8_encode(date('H\:i',time())) . ';' ; $dataLog .= helper::getIp($this->getData(['config','connect','anonymousIp'])) . ';'; $dataLog .= $this->getInput('userLoginId', helper::FILTER_ID) . ';' ; $dataLog .= $this->getUrl() .';' ; diff --git a/core/vendor/filemanager/config/config.php b/core/vendor/filemanager/config/config.php index 0ff4f6c..603bb49 100644 --- a/core/vendor/filemanager/config/config.php +++ b/core/vendor/filemanager/config/config.php @@ -3,15 +3,27 @@ $version = "9.14.0"; if (session_id() == '') session_start(); mb_internal_encoding('UTF-8'); -mb_http_output('UTF-8'); -mb_http_input('UTF-8'); +mb_http_output(); +mb_http_input(); mb_language('uni'); if (function_exists('mb_regex_encoding')) { mb_regex_encoding('UTF-8'); } ob_start('mb_output_handler'); -date_default_timezone_set('Europe/Paris'); -setlocale(LC_CTYPE, 'fr_FR'); //correct transliteration + +// Langage et locales fonction de la langue d'administration +$json = file_get_contents('../../../site/data/config.json'); +$tab = json_decode($json, true); +$langAdmin = $tab['config']['i18n']['langAdmin']; +if($langAdmin === 'fr'){ + date_default_timezone_set('Europe/Paris'); + setlocale(LC_CTYPE, 'fr_FR', 'fr'); //correct transliteration + $_SESSION['RF']['language']= 'fr_FR'; +} else { + date_default_timezone_set('Europe/London'); + setlocale(LC_CTYPE, 'en_GB', 'en'); //correct transliteration + $_SESSION['RF']['language']= 'en_EN'; +} /* Lecture du groupe de l'utilisateur connecté pour attribuer les droits et les dossiers */ $userId = $_COOKIE['DELTA_USER_ID']; diff --git a/module/blog/blog.php b/module/blog/blog.php index 8214bbb..3da490c 100644 --- a/module/blog/blog.php +++ b/module/blog/blog.php @@ -438,9 +438,9 @@ class blog extends common { ]); } self::$comments[] = [ - mb_detect_encoding(strftime('%d %B %Y - %H:%M', $comment['createdOn']), 'UTF-8', true) - ? strftime('%d %B %Y - %H:%M', $comment['createdOn']) - : utf8_encode(strftime('%d %B %Y - %H:%M', $comment['createdOn'])), + mb_detect_encoding(date('d\/m\/Y\ \-\ H\:i', $comment['createdOn']), 'UTF-8', true) + ? date('d\/m\/Y\ \-\ H\:i', $comment['createdOn']) + : utf8_encode(date('d\/m\/Y\ \-\ H\:i', $comment['createdOn'])), $comment['content'], $comment['userId'] ? $this->getData(['user', $comment['userId'], 'firstname']) . ' ' . $this->getData(['user', $comment['userId'], 'lastname']) : $comment['author'], $buttonApproval, @@ -675,12 +675,12 @@ class blog extends common { $approved = count($this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i],'comment'])); } // Met en forme le tableau - $date = mb_detect_encoding(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])), 'UTF-8', true) - ? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])) - : utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn']))); - $heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])), 'UTF-8', true) - ? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])) - : utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn']))); + $date = mb_detect_encoding(date('d\/m\/Y', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])), 'UTF-8', true) + ? date('d\/m\/Y', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])) + : utf8_encode(date('d\/m\/Y', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn']))); + $heure = mb_detect_encoding(date('H\:i', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])), 'UTF-8', true) + ? date('H\:i', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn'])) + : utf8_encode(date('H\:i', $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'publishedOn']))); self::$articles[] = [ '' . $this->getData(['module', $this->getUrl(0), 'posts', $articleIds[$i], 'title']) . diff --git a/module/blog/view/article/article.php b/module/blog/view/article/article.php index 96fd21e..98eb8a5 100644 --- a/module/blog/view/article/article.php +++ b/module/blog/view/article/article.php @@ -36,8 +36,19 @@ echo ''; // Pour les dates suivant la langue d'administration -setlocale(LC_TIME, 'fr_FR'); -if( $this->getData(['config', 'i18n', 'langAdmin']) === 'en') setlocale(LC_TIME, 'en_GB'); +$lang = 'fr_FR'; +$zone = 'Europe/Paris'; +if ( $this->getData(['config', 'i18n', 'langAdmin']) === 'en'){ + $lang = 'en_GB'; + $zone = 'Europe/London'; +} +$fmt = datefmt_create( + $lang, + IntlDateFormatter::LONG, + IntlDateFormatter::SHORT, + $zone, + IntlDateFormatter::GREGORIAN +); ?>
@@ -56,14 +67,7 @@ if( $this->getData(['config', 'i18n', 'langAdmin']) === 'en') setlocale(LC_TIME, - getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true) - ? strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])) - : utf8_encode(strftime('%d %B %Y', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))); - $heure = mb_detect_encoding(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])), 'UTF-8', true) - ? strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])) - : utf8_encode(strftime('%H:%M', $this->getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn']))); - echo $date .' - ' . $heure; - ?> + getData(['module', $this->getUrl(0), 'posts', $this->getUrl(1), 'publishedOn'])))); ?> getData(['config', 'i18n', 'langAdmin']) === 'en') setlocale(LC_TIME, $comment): ?>

-

diff --git a/module/blog/view/index/index.php b/module/blog/view/index/index.php index 14f04eb..3588929 100644 --- a/module/blog/view/index/index.php +++ b/module/blog/view/index/index.php @@ -10,10 +10,21 @@ switch ($val) { $text[0] = 'Read more'; break; } -?> -getData(['config', 'i18n', 'langAdmin']) === 'en') setlocale(LC_TIME, 'en_GB'); ?> - +// Pour les dates suivant la langue d'administration +$lang = 'fr_FR'; +$zone = 'Europe/Paris'; +if ( $this->getData(['config', 'i18n', 'langAdmin']) === 'en'){ + $lang = 'en_GB'; + $zone = 'Europe/London'; +} +$fmt = datefmt_create( + $lang, + IntlDateFormatter::LONG, + IntlDateFormatter::SHORT, + $zone, + IntlDateFormatter::GREGORIAN +); +if($module::$articles): ?>
$article): ?> @@ -51,9 +62,7 @@ if( $this->getData(['config', 'i18n', 'langAdmin']) === 'en') setlocale(LC_TIME,
- +

... diff --git a/module/form/form.php b/module/form/form.php index 7ff7eae..8768142 100644 --- a/module/form/form.php +++ b/module/form/form.php @@ -18,7 +18,7 @@ class form extends common { - const VERSION = '3.0'; + const VERSION = '4.0'; const REALNAME = 'Formulaire'; const DELETE = true; const UPDATE = '0.0'; @@ -26,6 +26,7 @@ class form extends common { public static $actions = [ 'config' => self::GROUP_MODERATOR, + 'update' => self::GROUP_MODERATOR, 'data' => self::GROUP_MODERATOR, 'delete' => self::GROUP_MODERATOR, 'deleteall' => self::GROUP_MODERATOR, @@ -49,6 +50,7 @@ class form extends common { const TYPE_DATETIME = 'date'; const TYPE_CHECKBOX = 'checkbox'; const TYPE_LABEL = 'label'; + const TYPE_FILE = 'file'; const ITEMSPAGE = 10; @@ -59,7 +61,8 @@ class form extends common { self::TYPE_MAIL => 'Champ mail', self::TYPE_SELECT => 'Sélection', self::TYPE_CHECKBOX => 'Case à cocher', - self::TYPE_DATETIME => 'Date' + self::TYPE_DATETIME => 'Date', + self::TYPE_FILE => 'fichier' ]; public static $types_en = [ self::TYPE_LABEL => 'Label', @@ -68,12 +71,13 @@ class form extends common { self::TYPE_MAIL => 'Mail field', self::TYPE_SELECT => 'Selection', self::TYPE_CHECKBOX => 'Check box', - self::TYPE_DATETIME => 'Date' + self::TYPE_DATETIME => 'Date', + self::TYPE_FILE => 'file' ]; public static $listUsers = [ ]; - + public static $signature = [ 'text' => 'Nom du site', 'logo' => 'Logo du site' @@ -88,7 +92,23 @@ class form extends common { '80' => '80%', '100' => '100%' ]; - + public static $maxSizeUpload = [ + '100000' => '100Ko', + '200000' => '200Ko', + '500000' => '500Ko', + '1000000' => '1Mo', + '2000000' => '2Mo', + '5000000' => '5Mo' + ]; + + /** + * Mise à jour du module + */ + public function update() { + if( null === $this->getData(['module', $this->getUrl(0), 'config', 'maxSizeUpload'])) $this->setData(['module', $this->getUrl(0), 'config', 'maxSizeUpload', '500000']); + } + + /** * Configuration */ @@ -131,7 +151,8 @@ class form extends common { 'replyto' => $this->getInput('formConfigMailReplyTo', helper::FILTER_BOOLEAN), 'signature' => $this->getInput('formConfigSignature'), 'logoUrl' => $this->getInput('formConfigLogo'), - 'logoWidth' => $this->getInput('formConfigLogoWidth') + 'logoWidth' => $this->getInput('formConfigLogoWidth'), + 'maxSizeUpload' => $this->getInput('formConfigMaxSize') ] ]); // Génération des données vides @@ -381,6 +402,8 @@ class form extends common { * Accueil */ public function index() { + // Mise à jour du module + $this->update(); // Lexique $text = []; $val = $this->getData(['config', 'i18n', 'langAdmin']); @@ -390,12 +413,24 @@ class form extends common { $text[1] = 'Nouveau message en provenance de votre site'; $text[2] = 'Nouveau message en provenance de la page "'; $text[3] = 'Formulaire soumis'; + $text[4] = 'La pièce jointe n\'est pas une image'; + $text[5] = '?'; + $text[6] = 'La taille du fichier excède '; + $text[7] = 'L\'extension du fichier doit être jpg, jpeg, png ou gif'; + $text[8] = 'Erreur pendant le téléversement du fichier'; + $text[9] = 'échec le message n\'est pas envoyé car '; break; case 'en' : $text[0] = 'Incorrect'; $text[1] = 'New message from your site'; $text[2] = 'New message from the page "'; $text[3] = 'Form submitted'; + $text[4] = 'File is not an image'; + $text[5] = '?'; + $text[6] = 'File size exceeds '; + $text[7] = 'The file extension must be jpg, jpeg, png or gif'; + $text[8] = 'Error while uploading file' ; + $text[9] = 'failure, the message is not sent because '; break; } // Soumission du formulaire @@ -413,20 +448,32 @@ class form extends common { $data = []; $replyTo = null; $content = ''; + // $notice concerne la pièce jointe + $notice = ''; foreach($this->getData(['module', $this->getUrl(0), 'input']) as $index => $input) { // Filtre la valeur switch($input['type']) { case self::TYPE_MAIL: $filter = helper::FILTER_MAIL; + $this->setData(['module', $this->getUrl(0), 'draft', 'mail', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_TEXTAREA: $filter = helper::FILTER_STRING_LONG; + $this->setData(['module', $this->getUrl(0), 'draft', 'textarea', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_DATETIME: $filter = helper::FILTER_STRING_SHORT; // Mettre TYPE_DATETIME pour récupérer un TIMESTAMP + $this->setData(['module', $this->getUrl(0), 'draft', 'datetime', $this->getInput('formInput[' . $index . ']')]); break; case self::TYPE_CHECKBOX: $filter = helper::FILTER_BOOLEAN; + $this->setData(['module', $this->getUrl(0), 'draft', 'checkbox', $this->getInput('formInput[' . $index . ']')]); + break; + case self::TYPE_SELECT: + $this->setData(['module', $this->getUrl(0), 'draft', 'select', $this->getInput('formInput[' . $index . ']')]); + break; + case self::TYPE_TEXT: + $this->setData(['module', $this->getUrl(0), 'draft', 'text', $this->getInput('formInput[' . $index . ']')]); break; default: $filter = helper::FILTER_STRING_SHORT; @@ -437,63 +484,129 @@ class form extends common { $input['type'] === 'mail') { $replyTo = $value; } + + // Traitement de la pièce jointe, fichier avec extension valide de taille maximum $sizeMax + // Fichier chargé dans site/file/uploads/ et effacé après l'envoi du mail + if( $input['type'] === 'file'){ + $target_dir = self::FILE_DIR.'uploads'; + $sizeMax = $this->getData(['module', $this->getUrl(0), 'config', 'maxSizeUpload']); + $extensions_valides = array( 'jpg' , 'jpeg' , 'gif' , 'png'); + $extensions_images = array( 'jpg' , 'jpeg' , 'gif' , 'png' ); + $file_name = basename($_FILES["fileToUpload"]["name"]); + if( $_FILES["fileToUpload"]["error"] === 0){ + if($file_name !== '' && $file_name !== null){ + if( ! is_dir( $target_dir )) mkdir( $target_dir, 0744); + // Copie du fichier .htaccess depuis module/form/ressource + copy('./module/form/ressource/.htaccess', $target_dir.'/.htaccess'); + $target_file = $target_dir .'/'. $file_name; + $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); + + // Vérification que la pièce jointe est une image quand son extension est celle d'une image + if( $_FILES["fileToUpload"]["tmp_name"] !== '' && $_FILES["fileToUpload"]["tmp_name"] !== null + && in_array($imageFileType,$extensions_images)){ + $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]); + if($check === false) $notice = $text[4]; + } + + // Vérification de la taille du fichier + if ($_FILES["fileToUpload"]["size"] > $sizeMax) $notice = $text[6].intval($sizeMax/1000).' Ko'; + + // Vérification des types de fichiers autorisés + if( ! in_array($imageFileType,$extensions_valides) ) $notice = $text[7]; + + // Upload du fichier + if ($notice === '') { + if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) { + $value = $file_name; + } else { + $notice = $text[8]; + } + } + } + } else { + switch($_FILES["fileToUpload"]["error"]) { + case 2 : + $notice = $text[6].' MAX_FILE_SIZE : 5Mo'; + break; + default: + $notice = $text[8]; + } + } + } + + // Préparation des données pour la création dans la base $data[$this->getData(['module', $this->getUrl(0), 'input', $index, 'name'])] = $value; // Préparation des données pour le mail $content .= '' . $this->getData(['module', $this->getUrl(0), 'input', $index, 'name']) . ' : ' . $value . '
'; } - // Crée les données - $this->setData(['module', $this->getUrl(0), 'data', helper::increment(1, $this->getData(['module', $this->getUrl(0), 'data'])), $data]); - // Envoi du mail - // Rechercher l'adresse en fonction du mail - $sent = true; - $singleuser = $this->getData(['user', - $this->getData(['module', $this->getUrl(0), 'config', 'user']), - 'mail']); - $singlemail = $this->getData(['module', $this->getUrl(0), 'config', 'mail']); - $group = $this->getData(['module', $this->getUrl(0), 'config', 'group']); - // Verification si le mail peut être envoyé - if( - self::$inputNotices === [] && ( - $group > 0 || - $singleuser !== '' || - $singlemail !== '' ) - ) { - // Utilisateurs dans le groupe - $to = []; - if ($group > 0){ - foreach($this->getData(['user']) as $userId => $user) { - if($user['group'] >= $group) { - $to[] = $user['mail']; + // Si absence d'erreur sur la pièce jointe + if( $notice === ''){ + // Crée les données + $this->setData(['module', $this->getUrl(0), 'data', helper::increment(1, $this->getData(['module', $this->getUrl(0), 'data'])), $data]); + $sent = true; + // Emission du mail + // Rechercher l'adresse en fonction du mail + $singleuser = $this->getData(['user', + $this->getData(['module', $this->getUrl(0), 'config', 'user']), + 'mail']); + $singlemail = $this->getData(['module', $this->getUrl(0), 'config', 'mail']); + $group = $this->getData(['module', $this->getUrl(0), 'config', 'group']); + // Verification si le mail peut être envoyé + if( + self::$inputNotices === [] && ( + $group > 0 || + $singleuser !== '' || + $singlemail !== '' ) + ) { + // Utilisateurs dans le groupe + $to = []; + if ($group > 0){ + foreach($this->getData(['user']) as $userId => $user) { + if($user['group'] >= $group) { + $to[] = $user['mail']; + } } } - } - // Utilisateur désigné - if (!empty($singleuser)) { - $to[] = $singleuser; - } - // Mail désigné - if (!empty($singlemail)) { - $to[] = $singlemail; - } - if($to) { - // Sujet du mail - $subject = $this->getData(['module', $this->getUrl(0), 'config', 'subject']); - if($subject === '') { - $subject = $text[1]; + // Utilisateur désigné + if (!empty($singleuser)) { + $to[] = $singleuser; + } + // Mail désigné + if (!empty($singlemail)) { + $to[] = $singlemail; + } + if($to) { + // Sujet du mail + $subject = $this->getData(['module', $this->getUrl(0), 'config', 'subject']); + if($subject === '') { + $subject = $text[1]; + } + // Envoi le mail + $sent = $this->sendMail( + $to, + $subject, + $text[2] . $this->getData(['page', $this->getUrl(0), 'title']) . '" :

' . + $content, + $replyTo, + $file_name + ); } - // Envoi le mail - $sent = $this->sendMail( - $to, - $subject, - $text[2] . $this->getData(['page', $this->getUrl(0), 'title']) . '" :

' . - $content, - $replyTo - ); } + // Nettoyage du dossier self::FILE_DIR.uploads + $FilesUpload = glob( self::FILE_DIR.'uploads/*'); + foreach($FilesUpload as $file) { + if(is_file($file)) unlink($file); + } + // Redirection + $redirect = helper::baseUrl() . $this->getUrl(0); + if ( $this->getData(['module', $this->getUrl(0), 'config', 'pageId']) !== '') $redirect = helper::baseUrl() . $this->getData(['module', $this->getUrl(0), 'config', 'pageId']); + // Effacement des données provisoires + $this->setData(['module', $this->getUrl(0), 'draft', '']); + } else { + $sent = false; + $redirect = helper::baseUrl() . $this->getUrl(0); } - // Redirection - $redirect = $this->getData(['module', $this->getUrl(0), 'config', 'pageId']); // Passage de la langue d'administration à flatpickr $lang_flatpickr = 'fr'; if( $this->getData(['config', 'i18n', 'langAdmin']) ==='en'){ @@ -506,9 +619,9 @@ class form extends common { addOutput([ - 'notification' => ($sent === true ? $text[3] : $sent), - 'redirect' => $redirect ? helper::baseUrl() . $redirect : '', - 'state' => ($sent === true ? true : null), + 'notification' => ($sent === true ? $text[3] : $notice), + 'redirect' => $redirect, + 'state' => ($sent === true ? true : false), 'vendor' => [ 'flatpickr' ], diff --git a/module/form/ressource/.htaccess b/module/form/ressource/.htaccess new file mode 100644 index 0000000..56c7477 --- /dev/null +++ b/module/form/ressource/.htaccess @@ -0,0 +1,4 @@ +# Interdire l'exécution de fichiers + +deny from all + diff --git a/module/form/view/config/config.php b/module/form/view/config/config.php index d676118..1c9d534 100644 --- a/module/form/view/config/config.php +++ b/module/form/view/config/config.php @@ -23,7 +23,7 @@ switch ($val) { $text[16] = 'A une adresse email'; $text[17] = 'Un email ou une liste de diffusion'; $text[18] = 'Répondre à l\'expéditeur depuis le mail de notification'; - $text[19] = 'Cette option permet de réponse drectement à l\'expéditeur du message si celui-ci a indiqué un email valide.'; + $text[19] = 'Cette option permet de répondre directement à l\'expéditeur du message si celui-ci a indiqué un email valide.'; $text[20] = 'Sélectionner le type de signature'; $text[21] = 'Sélectionnez le logo du site'; $text[22] = 'Logo'; @@ -35,6 +35,7 @@ switch ($val) { $text[28] = 'Le formulaire ne contient aucun champ.'; $text[29] = 'Version n°'; $text[30] = 'Enregistrer'; + $text[31] = 'Taille maximale de la pièce jointe'; $types = $module::$types; $signature = $module::$signature; break; @@ -70,6 +71,7 @@ switch ($val) { $text[28] = 'The form contains no fields'; $text[29] = 'Version no.'; $text[30] = 'Register'; + $text[31] = 'Maximum size of the attachment'; $types = $module::$types_en; $signature = $module::$signature_en; break; @@ -242,9 +244,20 @@ switch ($val) { ]); ?>

- $this->getData(['module', $this->getUrl(0), 'config', 'captcha']) - ]); ?> +
+
+ $this->getData(['module', $this->getUrl(0), 'config', 'captcha']) + ]); ?> +
+
+ $text[31], + 'selected' => $this->getData(['module', $this->getUrl(0), 'config', 'maxSizeUpload']) + ]); ?> +
+
+

diff --git a/module/form/view/index/index.css b/module/form/view/index/index.css new file mode 100644 index 0000000..3dd4a04 --- /dev/null +++ b/module/form/view/index/index.css @@ -0,0 +1,39 @@ +/** + * This file is part of DeltaCMS. + * For full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + * @author Sylvain Lelièvre + * @copyright Copyright (C) 2021-2022, Sylvain Lelièvre + * @license GNU General Public License, version 3 + * @link https://deltacms.fr/ + * + * Delta was created from version 11.2.00.24 of ZwiiCMS + * @author Rémi Jean + * @copyright Copyright (C) 2008-2018, Rémi Jean + * @author Frédéric Tempez + * @copyright Copyright (C) 2018-2021, Frédéric Tempez + */ + + +#formFileReset { + background-color: red; + border-width:1px; + border-color: orange; + font-size: 1.15em; + font-style: bold; + color: yellow; +} + +#formFileReset:hover { + background-color: orange; + border-color: orange; + font-style: normal; + color:black; +} + +.formInputFile { + padding: 9px; + border-radius: 2px; + border: 1px solid #D8DFE3; + backgroung-color: rgba(255,255,255,1); +} \ No newline at end of file diff --git a/module/form/view/index/index.js.php b/module/form/view/index/index.js.php index 0045a00..b01fc0a 100644 --- a/module/form/view/index/index.js.php +++ b/module/form/view/index/index.js.php @@ -15,3 +15,6 @@ */ +$( "#formFileReset" ).click(function() { + $( "#fileToUpload" ).val(''); +}); diff --git a/module/form/view/index/index.php b/module/form/view/index/index.php index 1538ee0..7224d79 100644 --- a/module/form/view/index/index.php +++ b/module/form/view/index/index.php @@ -14,12 +14,13 @@ switch ($val) { } ?> getData(['module', $this->getUrl(0), 'input'])): ?> - + getData(['module', $this->getUrl(0), 'input']) as $index => $input): ?> 'formInput_' . $index, - 'label' => $input['name'] + 'label' => $input['name'], + 'value' => $this->getData([ 'module', $this->getUrl(0), 'draft', 'mail']) ]); ?> 'formInput_' . $index, - 'label' => $input['name'] + 'label' => $input['name'], + 'value' => $this->getData([ 'module', $this->getUrl(0), 'draft', 'select']) ]); ?> 'formInput_' . $index, - 'label' => $input['name'] + 'label' => $input['name'], + 'value' => $this->getData([ 'module', $this->getUrl(0), 'draft', 'text']) ]); ?> 'formInput_' . $index, - 'label' => $input['name'] + 'label' => $input['name'], + 'value' => $this->getData([ 'module', $this->getUrl(0), 'draft', 'textarea']) ]); ?> 'formInput_' . $index, 'label' => $input['name'], - 'vendor' => 'flatpickr' + 'vendor' => 'flatpickr', + 'value' => $this->getData([ 'module', $this->getUrl(0), 'draft', 'datetime']) ]); ?> - + $this->getData([ 'module', $this->getUrl(0), 'draft', 'checkbox']) + ]); ?> + + + + + +
+ + + +

-

- -
-

+

getData(['module', $this->getUrl(0), 'config', 'captcha'])): ?> diff --git a/module/gallery/gallery.php b/module/gallery/gallery.php index e672ee0..ec0c812 100644 --- a/module/gallery/gallery.php +++ b/module/gallery/gallery.php @@ -675,7 +675,7 @@ class gallery extends common { // Tri des images switch ($this->getData(['module', $this->getUrl(0), 'content', $this->getUrl(2), 'config', 'sort'])) { case self::SORT_HAND: - $positions = $this->getdata(['module',$this->getUrl(0), $this->getUrl(2),'positions']); + $positions = $this->getdata(['module',$this->getUrl(0),'content', $this->getUrl(2),'positions']); if ($positions) { foreach ($positions as $key => $value) { if (array_key_exists($key,self::$pictures)) { diff --git a/module/gallery/view/edit/edit.js.php b/module/gallery/view/edit/edit.js.php index 3cba9ec..9b411ba 100644 --- a/module/gallery/view/edit/edit.js.php +++ b/module/gallery/view/edit/edit.js.php @@ -68,11 +68,7 @@ $( document ).ready(function() { $("#galleryTable").tableDnD({ onDrop: function(table, row) { $("#galleryEditFormResponse").val($.tableDnD.serialize()); - }, - onDragStop : function(table, row) { - // Sauvegarde le tri sortPictures(); - $("#galleryEditFormResponse").val(""); }, serializeRegexp: "" }); diff --git a/module/statislite/include/stat.php b/module/statislite/include/stat.php index 1f0047f..43dc7cd 100644 --- a/module/statislite/include/stat.php +++ b/module/statislite/include/stat.php @@ -146,7 +146,9 @@ if( file_exists($fichiers_json.'filtre_primaire.json')){ //Initialisation si c'est un nouvel indice if(!isset($log[$indice])){ - $log[$indice] = array('ip' => $ip, 'user_id'=> $delta_user_id, 'userAgent' => $_SERVER['HTTP_USER_AGENT'], 'langage' => $_SERVER['HTTP_ACCEPT_LANGUAGE'], 'referer' => $_SERVER['HTTP_REFERER'], 'vues' => array(), 'client' => array() ); + $referer = ''; + if( isset( $_SERVER['HTTP_REFERER'] )) $referer = $_SERVER['HTTP_REFERER']; + $log[$indice] = array('ip' => $ip, 'user_id'=> $delta_user_id, 'userAgent' => $_SERVER['HTTP_USER_AGENT'], 'langage' => $_SERVER['HTTP_ACCEPT_LANGUAGE'], 'referer' => $referer, 'vues' => array(), 'client' => array() ); } // Ajout de la vue sous la forme date et page vue $indice2 = count($log[$indice]['vues']); diff --git a/module/statislite/statislite.php b/module/statislite/statislite.php index ef88a2d..53dc13e 100644 --- a/module/statislite/statislite.php +++ b/module/statislite/statislite.php @@ -605,12 +605,12 @@ class statislite extends common { // Sauvegarde de sécurité des fichiers json $this->sauvegardeJson(); // Réinitialisation des fichiers json - $this -> initcumul(); - $this -> initchrono(); - file_put_contents( self::$fichiers_json.'robots.json', '{}'); - file_put_contents( self::$fichiers_json.'sessionInvalide.json', '{}'); - file_put_contents( self::$fichiers_json.'affitampon.json', '{}'); - file_put_contents( self::$fichiers_json.'sessionLog.json', '{}'); + $this -> initcumul(); + $this -> initchrono(); + file_put_contents( self::$fichiers_json.'robots.json', '{}'); + file_put_contents( self::$fichiers_json.'sessionInvalide.json', '{}'); + file_put_contents( self::$fichiers_json.'affitampon.json', '{}'); + file_put_contents( self::$fichiers_json.'sessionLog.json', '{}'); // Valeurs en sortie $this->addOutput([ 'redirect' => helper::baseUrl() . $this->getUrl(0) . '/config', @@ -846,7 +846,9 @@ class statislite extends common { $log[$numSession]['vues'] = $tableau[$numSession]['vues']; $nbpageparsession = count($log[$numSession]['vues']); } - $ip = $log[$numSession]['ip']; + if(isset($log[$numSession]['ip'])){ + $ip = $log[$numSession]['ip']; + } $datetimei = strtotime(substr($log[$numSession]['vues'][0], 0 , 19)); // Si $nbpageparsession <=1 on force la valeur de $datetimef if($nbpageparsession <= 1){ @@ -884,10 +886,10 @@ class statislite extends common { $log[$numSession]['client'][2] = $this->systeme($log[$numSession]['userAgent']); // Geolocalisation si elle n'a pas été faite et si l'IP n'est pas déjà détruite if(isset($log[$numSession]['ip'])){ - if($geolocalisation && ! isset($log[$numSession]['geolocalisation'])){ + /*if($geolocalisation && ! isset($log[$numSession]['geolocalisation'])){ $geo = $this->geolocalise($log[$numSession]['ip']); $log[$numSession]['geolocalisation'] = $geo['country_name'].' - '.$geo['city']; - } + }*/ // CNIL : ne pas mémoriser d'adresse IP unset($log[$numSession]['ip']); } @@ -998,8 +1000,10 @@ class statislite extends common { $nom = substr($value, 22 , strlen($value)); //$date = strtotime(substr($value, 0 , 19)); ajouter dans le if && ( strtotime(substr($tab[$numSession]['vues'][$i], 0 , 19)) - $date) < 60) for($i=$key + 1 ; $i < $nbpageparsession; $i++){ - if( substr($tab[$numSession]['vues'][$i], 22 , strlen($tab[$numSession]['vues'][$i])) == $nom){ - unset($tab[$numSession]['vues'][$i]); + if( isset ($tab[$numSession]['vues'][$i])){ + if( substr($tab[$numSession]['vues'][$i], 22 , strlen($tab[$numSession]['vues'][$i])) == $nom){ + unset($tab[$numSession]['vues'][$i]); + } } } } @@ -1063,7 +1067,7 @@ class statislite extends common { } // Geolocalisation - if($log[$numSession]['geolocalisation'] != 'Fichier - clef_ipapi_com.txt - absent , .'){ + /*if($log[$numSession]['geolocalisation'] != 'Fichier - clef_ipapi_com.txt - absent , .'){ // Extraction du pays $postiret = strpos($log[$numSession]['geolocalisation'], '-'); $pays = substr($log[$numSession]['geolocalisation'], 0, $postiret - 1); @@ -1080,6 +1084,7 @@ class statislite extends common { $cumul['clients']['localisation'][$pays] = 1; } } + */ // Mise à jour des variables liées au fichier sessionLog.json self::$comptepages = self::$comptepages - $nbpageparsession; @@ -1311,9 +1316,11 @@ class statislite extends common { } $tampon = $tableau; $nbsessiontampon = count($tampon); - for($i=0; $i < $nbEnregSession; $i++){ - self::$affidetaille[$i] = $tampon[$nbsessiontampon - 1 - $i]; - if($nbsessiontampon - 1 - $i == 0){ break;} + if( $nbsessiontampon > 0 ){ + for($i=0; $i < $nbEnregSession; $i++){ + self::$affidetaille[$i] = $tampon[$nbsessiontampon - 1 - $i]; + if($nbsessiontampon - 1 - $i === 0) break; + } } // Valeurs en sortie @@ -1402,7 +1409,7 @@ class statislite extends common { /* Geolocalisation */ /* Utilisation de cette fonction supprimée */ - private function geolocalise($ip){ + /*private function geolocalise($ip){ // Géolocalisation avec le site www.ipapi.com qui offre 10000 requêtes / mois if( is_file(self::$base.'clef_ipapi_com.txt')){ $access_key = file_get_contents(self::$base.'clef_ipapi_com.txt'); @@ -1420,6 +1427,7 @@ class statislite extends common { } return $api_result; } + */ /* Initialisation de cumul.json */ private function initcumul(){