From a0ef6022973d04056a1a7480a63c8888d16af7b5 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 16 Nov 2022 11:12:34 +0100 Subject: [PATCH 01/64] Fix ODT generation : htmlspecialchars() was run too many times on some strings. --- htdocs/includes/odtphp/odf.php | 57 ++++-- test/phpunit/ODFTest.php | 363 +++++++++++++++++++++++++++++++++ 2 files changed, 406 insertions(+), 14 deletions(-) create mode 100644 test/phpunit/ODFTest.php diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index b780b550b6d..a07f5346943 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -15,6 +15,7 @@ class OdfException extends Exception * @copyright 2010-2015 - Laurent Destailleur - eldy@users.sourceforge.net * @copyright 2010 - Vikas Mahajan - http://vikasmahajan.wordpress.com * @copyright 2012 - Stephen Larroque - lrq3000@gmail.com + * @copyright 2020 - Open-DSI - contact@open-dsi.fr * @license https://www.gnu.org/copyleft/gpl.html GPL License * @version 1.5.0 */ @@ -43,6 +44,8 @@ class Odf public $userdefined=array(); const PIXEL_TO_CM = 0.026458333; + const FIND_ENCODED_TAGS_REGEX = '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/'; + /** * Class constructor @@ -156,12 +159,16 @@ class Odf */ public function convertVarToOdf($value, $encode = true, $charset = 'ISO-8859') { - $value = $encode ? htmlspecialchars($value) : $value; - $value = ($charset == 'ISO-8859') ? utf8_encode($value) : $value; + $value = html_entity_decode($value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401); + + // fix breaklines... + $value = str_replace("
", "
", $value); $convertedValue = $value; // Check if the value includes html tags if ($this->_hasHtmlTag($value) === true) { + $value = strip_tags($value, ['
', '', '', '', '', '', '', '', '', '']); + // Default styles for strong/b, i/em, u, s, sub & sup $automaticStyles = array( '', @@ -172,7 +179,7 @@ class Odf '' ); - $convertedValue = $this->_replaceHtmlWithOdtTag($this->_getDataFromHtml($value), $customStyles, $fontDeclarations); + $convertedValue = $this->_replaceHtmlWithOdtTag($this->_getDataFromHtml($value), $customStyles, $fontDeclarations, $encode, $charset); foreach ($customStyles as $key => $val) { array_push($automaticStyles, '' . $val . ''); @@ -195,20 +202,26 @@ class Odf } } $this->contentXml = str_replace('', $fonts . '', $this->contentXml); + } + else { + $convertedValue = $this->encode_chars($convertedValue, $encode, $charset); } - else $convertedValue = preg_replace('/(\r\n|\r|\n)/i', "", $value); + + $convertedValue = preg_replace('/(\r\n|\r|\n)/i', "", $convertedValue); return $convertedValue; } /** - * Replaces html tags in with odt tags and returns an odt string + * Replaces html tags in with odt tags and returns an odt string. Encodes and converts inner text. * @param array $tags An array with html tags generated by the getDataFromHtml() function * @param array $customStyles An array of style defenitions that should be included inside the odt file * @param array $fontDeclarations An array of font declarations that should be included inside the odt file + * @param bool $encode If true, special XML characters are encoded + * @param string $charset Charset * @return string */ - private function _replaceHtmlWithOdtTag($tags, &$customStyles, &$fontDeclarations) + private function _replaceHtmlWithOdtTag($tags, &$customStyles, &$fontDeclarations, $encode = false, $charset = '') { if ($customStyles == null) $customStyles = array(); if ($fontDeclarations == null) $fontDeclarations = array(); @@ -218,7 +231,8 @@ class Odf foreach ((array) $tags as $tag) { // Check if the current item is a tag or just plain text if (isset($tag['text'])) { - $odtResult .= $tag['text']; + $text = $this->encode_chars($tag['text'], $encode, $charset); + $odtResult .= $text; } elseif (isset($tag['name'])) { switch ($tag['name']) { case 'br': @@ -226,23 +240,23 @@ class Odf break; case 'strong': case 'b': - $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . ''; + $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . ''; break; case 'i': case 'em': - $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . ''; + $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . ''; break; case 'u': - $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . ''; + $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . ''; break; case 's': - $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . ''; + $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . ''; break; case 'sub': - $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . ''; + $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . ''; break; case 'sup': - $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . ''; + $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . ''; break; case 'span': if (isset($tag['attributes']['style'])) { @@ -279,7 +293,7 @@ class Odf // Generate a unique id for the style (using microtime and random because some CPUs are really fast...) $key = floatval(str_replace('.', '', microtime(true)))+rand(0, 10); $customStyles[$key] = $odtStyles; - $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . ''; + $odtResult .= '' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . ''; } } break; @@ -292,6 +306,21 @@ class Odf return $odtResult; } + /** + * Correctly encode chars + * @param string $text The text to encode or not + * @param bool $encode If true, special XML characters are encoded + * @param string $charset Charset + * @return string The converted text + * @see self::convertVarToOdf() + */ + private function encode_chars($text, $encode = false, $charset = '') + { + $newtext = $encode ? htmlspecialchars($text, ENT_QUOTES | ENT_XML1) : $text; + $newtext = ($charset == 'ISO-8859') ? utf8_encode($newtext) : $newtext; + return $newtext; + } + /** * Checks if the given text is a html string * @param string $text The text to check diff --git a/test/phpunit/ODFTest.php b/test/phpunit/ODFTest.php new file mode 100644 index 00000000000..989a42c93bf --- /dev/null +++ b/test/phpunit/ODFTest.php @@ -0,0 +1,363 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file test/unit/BillOfMaterialsTest.php + * \ingroup billofmaterials + * \brief PHPUnit test for BillOfMaterials class. + */ + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; +require_once dirname(__FILE__).'/../../htdocs/master.inc.php'; +require_once dirname(__FILE__).'/../../htdocs/includes/odtphp/odf.php'; + +if (empty($user->id)) { + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + $user->getrights(); +} +$conf->global->MAIN_DISABLE_ALL_MAILS=1; + +$langs->load("main"); + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class ODFTest extends PHPUnit\Framework\TestCase +{ + protected $savconf; + protected $savuser; + protected $savlangs; + protected $savdb; + + /** + * Constructor + * We save global variables into local variables + * + * @return BOMTest + */ + public function __construct() + { + parent::__construct(); + + //$this->sharedFixture + global $conf,$user,$langs,$db; + $this->savconf=$conf; + $this->savuser=$user; + $this->savlangs=$langs; + $this->savdb=$db; + + print __METHOD__." db->type=".$db->type." user->id=".$user->id; + //print " - db ".$db->db; + print "\n"; + } + + /** + * setUpBeforeClass + * + * @return void + */ + public static function setUpBeforeClass() + { + global $conf,$user,$langs,$db; + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + print __METHOD__."\n"; + } + + /** + * tearDownAfterClass + * + * @return void + */ + public static function tearDownAfterClass() + { + global $conf,$user,$langs,$db; + $db->rollback(); + + print __METHOD__."\n"; + } + + /** + * Init phpunit tests + * + * @return void + */ + protected function setUp() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + print __METHOD__."\n"; + } + + /** + * End phpunit tests + * + * @return void + */ + protected function tearDown() + { + print __METHOD__."\n"; + } + + /** + * test ODF convertVarToOdf + * + * @return int + */ + public function testODFconvertVarToOdf() + { + global $conf,$user,$langs,$db; + $conf=$this->savconf; + $user=$this->savuser; + $langs=$this->savlangs; + $db=$this->savdb; + + // we test using template_invoice, it does not matter, we just need a valid odt. + $filename = '../../htdocs/install/doctemplates/invoices/template_invoice.odt'; + $config = [ + 'PATH_TO_TMP' => "/tmp", + 'ZIP_PROXY' => "PclZipProxy", + 'DELIMITER_LEFT' => "{", + 'DELIMITER_RIGHT' => "}", + ]; + + $to_test = [ + /** No HTML **/ + // Simple strings + 1 => [ + 'to_convert' => 'Simple string', + 'encode' => true, + 'charset' => null, + 'expected' => 'Simple string' + ], + 2 => [ + 'to_convert' => 'Simple string', + 'encode' => false, + 'charset' => null, + 'expected' => 'Simple string' + ], + 3 => [ + 'to_convert' => "Simple string\nwith line break", + 'encode' => true, + 'charset' => null, + 'expected' => "Simple stringwith line break" + ], + 4 => [ + 'to_convert' => "Simple string\nwith line break", + 'encode' => false, + 'charset' => null, + 'expected' => "Simple stringwith line break" + ], + // Special chars + 5 => [ + 'to_convert' => 'One&two', + 'encode' => true, + 'charset' => null, + 'expected' => 'One&two' + ], + 6 => [ + 'to_convert' => 'One&two', + 'encode' => false, + 'charset' => null, + 'expected' => 'One&two' + ], + 7 => [ + 'to_convert' => "/a&él'èàüöç€Ğ~<>", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode("/a&él'èàüöç€Ğ~<>"), + ], + 8 => [ + 'to_convert' => "/a&él'èàüöç€Ğ~<>", + 'encode' => false, + 'charset' => null, + 'expected' => utf8_encode("/a&él'èàüöç€Ğ~<>"), + ], + // special chars with non-default charset + 9 => [ + 'to_convert' => "/a&él'èàüöç€Ğ~<>", + 'encode' => true, + 'charset' => 'UTF-16', + 'expected' => "/a&él'èàüöç€Ğ~<>", + ], + 10 => [ + 'to_convert' => "/a&él'èàüöç€Ğ~<>", + 'encode' => false, + 'charset' => 'UTF-16', // When the charset differs from ISO-8859 string is not converted. + 'expected' => "/a&él'èàüöç€Ğ~<>", + ], + 11 => [ + 'to_convert' => "Greater > than", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode("Greater > than"), + ], + 12 => [ + 'to_convert' => "Greater > than", + 'encode' => false, + 'charset' => null, + 'expected' => utf8_encode("Greater > than"), + ], + 13 => [ + 'to_convert' => "Smaller < than", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode("Smaller < than"), + ], + 14 => [ + 'to_convert' => "Smaller < than", + 'encode' => false, + 'charset' => null, + 'expected' => utf8_encode("Smaller < than"), + ], + /** HTML **/ + // break lines + 15 => [ + 'to_convert' => "Break
line", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode("Breakline"), + ], + 16 => [ + 'to_convert' => "Break
line", + 'encode' => false, + 'charset' => null, + 'expected' => utf8_encode("Breakline"), + ], + 17 => [ + 'to_convert' => "Break
line", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode("Breakline"), + ], + 18 => [ + 'to_convert' => "Break
line", + 'encode' => false, + 'charset' => null, + 'expected' => utf8_encode("Breakline"), + ], + // HTML tags + 19 => [ + 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", + 'encode' => false, + 'charset' => 'UTF-8', + 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', + ], + 20 => [ + 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", + 'encode' => true, + 'charset' => 'UTF-8', + 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', + ], + 21 => [ + 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", + 'encode' => false, + 'charset' => null, + 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), + ], + 22 => [ + 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), + ], + 23 => [ + 'to_convert' => "text with intricatedtags", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode('text with intricatedtags'), + ], + + // One can also pass html-encoded string to the method + 24 => [ + 'to_convert' => 'One&two', + 'encode' => true, + 'charset' => null, + 'expected' => 'One&two' + ], + 25 => [ + 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", + 'encode' => false, + 'charset' => 'UTF-8', + 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', + ], + 26 => [ + 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", + 'encode' => true, + 'charset' => 'UTF-8', + 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', + ], + 27 => [ + 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", + 'encode' => false, + 'charset' => null, + 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), + ], + 28 => [ + 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", + 'encode' => true, + 'charset' => null, + 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), + ], + + // // TODO custom styles are not tested for now : the custom style have a custom ID based on time. Not random, but hard to mock or predict. generated in _replaceHtmlWithOdtTag() case 'span'. + // [ + // 'to_convert' => '123 trucmachin > truc < troc > tracbla bla', + // 'encode' => true, + // 'charset' => 'UTF-8', + // 'expected' => "123 trucmachin > truc < troc > tracbla bla'", + // ], + + // The method removes hyperlinks and tags that are not dealt with. + 29 => [ + 'to_convert' => '123 trucmachin > truc < troc > tracbla bla', + 'encode' => true, + 'charset' => null, + 'expected' => "123 trucmachin > truc < troc > tracbla bla", + ], + ]; + + $odf=new Odf($filename, array()); + if (is_object($odf)) $result = 1; // Just to test + + foreach ($to_test as $case) { + if ($case['charset'] !== null) { + $res = $odf->convertVarToOdf($case['to_convert'], $case['encode'], $case['charset']); + } else { + $res = $odf->convertVarToOdf($case['to_convert'], $case['encode']); + } + $this->assertEquals($res, $case['expected']); + } + + print __METHOD__." result=".$result."\n"; + + return $result; + } +} From b0548213b94aab7fceccbdd572a8589631b33952 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 16 Nov 2022 11:44:46 +0100 Subject: [PATCH 02/64] copyright and doc --- htdocs/includes/odtphp/odf.php | 2 +- test/phpunit/ODFTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index a07f5346943..9612a4c41a5 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -15,7 +15,7 @@ class OdfException extends Exception * @copyright 2010-2015 - Laurent Destailleur - eldy@users.sourceforge.net * @copyright 2010 - Vikas Mahajan - http://vikasmahajan.wordpress.com * @copyright 2012 - Stephen Larroque - lrq3000@gmail.com - * @copyright 2020 - Open-DSI - contact@open-dsi.fr + * @copyright 2022 - Open-DSI - contact@open-dsi.fr * @license https://www.gnu.org/copyleft/gpl.html GPL License * @version 1.5.0 */ diff --git a/test/phpunit/ODFTest.php b/test/phpunit/ODFTest.php index 989a42c93bf..7c859173326 100644 --- a/test/phpunit/ODFTest.php +++ b/test/phpunit/ODFTest.php @@ -1,6 +1,6 @@ - * Copyright (C) ---Put here your own copyright and developer email--- + * Copyright (C) 2022 - Open-DSI * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,9 +17,9 @@ */ /** - * \file test/unit/BillOfMaterialsTest.php - * \ingroup billofmaterials - * \brief PHPUnit test for BillOfMaterials class. + * \file test/unit/ODFTest.php + * \ingroup odf + * \brief PHPUnit test for odf class. */ global $conf,$user,$langs,$db; From a00331c4789ed0d5c2039f0b87ff3e0e5b335266 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 16 Nov 2022 12:07:07 +0100 Subject: [PATCH 03/64] Inline comment --- htdocs/includes/odtphp/odf.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index 9612a4c41a5..a5fb62e7218 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -167,6 +167,7 @@ class Odf // Check if the value includes html tags if ($this->_hasHtmlTag($value) === true) { + // Note: allowing many tags is supported on PHP >7.4 . For older versions, this will strip all HTML tags. $value = strip_tags($value, ['
', '', '', '', '', '', '', '', '', '']); // Default styles for strong/b, i/em, u, s, sub & sup From 00c62bf150b83cd668b42c10d33b501d4a543f2a Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 16 Nov 2022 14:08:41 +0100 Subject: [PATCH 04/64] Consistent management of carriage returns --- htdocs/includes/odtphp/odf.php | 2 +- test/phpunit/ODFTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index a5fb62e7218..9254ed709df 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -206,9 +206,9 @@ class Odf } else { $convertedValue = $this->encode_chars($convertedValue, $encode, $charset); + $convertedValue = preg_replace('/(\r\n|\r|\n)/i', "", $convertedValue); } - $convertedValue = preg_replace('/(\r\n|\r|\n)/i', "", $convertedValue); return $convertedValue; } diff --git a/test/phpunit/ODFTest.php b/test/phpunit/ODFTest.php index 7c859173326..5bcd9a72290 100644 --- a/test/phpunit/ODFTest.php +++ b/test/phpunit/ODFTest.php @@ -342,6 +342,14 @@ class ODFTest extends PHPUnit\Framework\TestCase 'charset' => null, 'expected' => "123 trucmachin > truc < troc > tracbla bla", ], + + // HTML should not take \n into account, but only
. + 30 => [ + 'to_convert' => "text with strong text , a line\nbreak and underlined words with it@lic sp&ciàlchärs éè l'", + 'encode' => false, + 'charset' => 'UTF-8', + 'expected' => 'text with strong text , a line'."\n".'break and underlined words with it@lic sp&ciàlchärs éè l\'', + ], ]; $odf=new Odf($filename, array()); From df761ceef7fd1ec1f0d68131b2a690ffb9cc9edf Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 23 Nov 2022 11:56:01 +0100 Subject: [PATCH 05/64] Use a constant for HTML tags regex --- htdocs/includes/odtphp/odf.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index 9254ed709df..4a24afafffd 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -44,6 +44,7 @@ class Odf public $userdefined=array(); const PIXEL_TO_CM = 0.026458333; + const FIND_TAGS_REGEX = '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/'; const FIND_ENCODED_TAGS_REGEX = '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/'; @@ -329,7 +330,7 @@ class Odf */ private function _isHtmlTag($text) { - return preg_match('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $text); + return preg_match(self::FIND_TAGS_REGEX, $text); } /** @@ -339,7 +340,7 @@ class Odf */ private function _hasHtmlTag($text) { - $result = preg_match_all('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $text); + $result = preg_match_all(self::FIND_TAGS_REGEX, $text); return is_numeric($result) && $result > 0; } @@ -355,7 +356,7 @@ class Odf while (strlen($tempHtml) > 0) { // Check if the string includes a html tag - if (preg_match_all('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $tempHtml, $matches)) { + if (preg_match_all(self::FIND_TAGS_REGEX, $tempHtml, $matches)) { $tagOffset = strpos($tempHtml, $matches[0][0]); // Check if the string starts with the html tag if ($tagOffset > 0) { From 95781e39c2ea6bee1d905872d42085373ab194b8 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 23 Nov 2022 11:56:51 +0100 Subject: [PATCH 06/64] Fix HTML tags regex: headings such as

are also HTML tags --- htdocs/includes/odtphp/odf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index 4a24afafffd..4e4287ae3b6 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -44,7 +44,7 @@ class Odf public $userdefined=array(); const PIXEL_TO_CM = 0.026458333; - const FIND_TAGS_REGEX = '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/'; + const FIND_TAGS_REGEX = '/<([A-Za-z0-9]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/'; const FIND_ENCODED_TAGS_REGEX = '/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/'; From e10ba35387c00ccffdb734e922cddfe4622e4614 Mon Sep 17 00:00:00 2001 From: Thomas Negre Date: Wed, 23 Nov 2022 12:01:21 +0100 Subject: [PATCH 07/64] Add test case to lock/explain behavior on

heading tags. --- test/phpunit/ODFTest.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/phpunit/ODFTest.php b/test/phpunit/ODFTest.php index 5bcd9a72290..90b505e0848 100644 --- a/test/phpunit/ODFTest.php +++ b/test/phpunit/ODFTest.php @@ -335,6 +335,9 @@ class ODFTest extends PHPUnit\Framework\TestCase // 'expected' => "123 trucmachin > truc < troc > tracbla bla'", // ], + /* Tests that can evolve */ + // Following tests reflect the current behavior. They may evolve if the method behavior changes. + // The method removes hyperlinks and tags that are not dealt with. 29 => [ 'to_convert' => '123 trucmachin > truc < troc > tracbla bla', @@ -342,9 +345,14 @@ class ODFTest extends PHPUnit\Framework\TestCase 'charset' => null, 'expected' => "123 trucmachin > truc < troc > tracbla bla", ], - - // HTML should not take \n into account, but only
. 30 => [ + 'to_convert' => '123

Title

bla', + 'encode' => true, + 'charset' => null, + 'expected' => "123 Title bla", + ], + // HTML should not take \n into account, but only
. + 31 => [ 'to_convert' => "text with strong text , a line\nbreak and underlined words with it@lic sp&ciàlchärs éè l'", 'encode' => false, 'charset' => 'UTF-8', From 32520599e450c4621ac03f9fdb37ad24513e7707 Mon Sep 17 00:00:00 2001 From: tnegre Date: Fri, 3 Feb 2023 15:12:05 +0100 Subject: [PATCH 08/64] ODT generation : tests cases for PHP < 7.4 --- test/phpunit/ODFTest.php | 101 ++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 33 deletions(-) diff --git a/test/phpunit/ODFTest.php b/test/phpunit/ODFTest.php index 90b505e0848..02c80dc9689 100644 --- a/test/phpunit/ODFTest.php +++ b/test/phpunit/ODFTest.php @@ -155,87 +155,101 @@ class ODFTest extends PHPUnit\Framework\TestCase 'to_convert' => 'Simple string', 'encode' => true, 'charset' => null, - 'expected' => 'Simple string' + 'expected7.4' => 'Simple string', + 'expected7.3' => 'Simple string' ], 2 => [ 'to_convert' => 'Simple string', 'encode' => false, 'charset' => null, - 'expected' => 'Simple string' + 'expected7.4' => 'Simple string', + 'expected7.3' => 'Simple string' ], 3 => [ 'to_convert' => "Simple string\nwith line break", 'encode' => true, 'charset' => null, - 'expected' => "Simple stringwith line break" + 'expected7.4' => "Simple stringwith line break", + 'expected7.3' => "Simple stringwith line break" ], 4 => [ 'to_convert' => "Simple string\nwith line break", 'encode' => false, 'charset' => null, - 'expected' => "Simple stringwith line break" + 'expected7.4' => "Simple stringwith line break", + 'expected7.3' => "Simple stringwith line break" ], // Special chars 5 => [ 'to_convert' => 'One&two', 'encode' => true, 'charset' => null, - 'expected' => 'One&two' + 'expected7.4' => 'One&two', + 'expected7.3' => 'One&two' ], 6 => [ 'to_convert' => 'One&two', 'encode' => false, 'charset' => null, - 'expected' => 'One&two' + 'expected7.4' => 'One&two', + 'expected7.3' => 'One&two' ], 7 => [ 'to_convert' => "/a&él'èàüöç€Ğ~<>", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode("/a&él'èàüöç€Ğ~<>"), + 'expected7.4' => utf8_encode("/a&él'èàüöç€Ğ~<>"), + 'expected7.3' => utf8_encode("/a&él'èàüöç€Ğ~<>") ], 8 => [ 'to_convert' => "/a&él'èàüöç€Ğ~<>", 'encode' => false, 'charset' => null, - 'expected' => utf8_encode("/a&él'èàüöç€Ğ~<>"), + 'expected7.4' => utf8_encode("/a&él'èàüöç€Ğ~<>"), + 'expected7.3' => utf8_encode("/a&él'èàüöç€Ğ~<>") ], // special chars with non-default charset 9 => [ 'to_convert' => "/a&él'èàüöç€Ğ~<>", 'encode' => true, 'charset' => 'UTF-16', - 'expected' => "/a&él'èàüöç€Ğ~<>", + 'expected7.4' => "/a&él'èàüöç€Ğ~<>", + 'expected7.3' => "/a&él'èàüöç€Ğ~<>", ], 10 => [ 'to_convert' => "/a&él'èàüöç€Ğ~<>", 'encode' => false, 'charset' => 'UTF-16', // When the charset differs from ISO-8859 string is not converted. - 'expected' => "/a&él'èàüöç€Ğ~<>", + 'expected7.4' => "/a&él'èàüöç€Ğ~<>", + 'expected7.3' => "/a&él'èàüöç€Ğ~<>", ], 11 => [ 'to_convert' => "Greater > than", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode("Greater > than"), + 'expected7.4' => utf8_encode("Greater > than"), + 'expected7.3' => utf8_encode("Greater > than"), ], 12 => [ 'to_convert' => "Greater > than", 'encode' => false, 'charset' => null, - 'expected' => utf8_encode("Greater > than"), + 'expected7.4' => utf8_encode("Greater > than"), + 'expected7.3' => utf8_encode("Greater > than"), ], 13 => [ 'to_convert' => "Smaller < than", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode("Smaller < than"), + 'expected7.4' => utf8_encode("Smaller < than"), + 'expected7.3' => utf8_encode("Smaller < than"), ], 14 => [ 'to_convert' => "Smaller < than", 'encode' => false, 'charset' => null, - 'expected' => utf8_encode("Smaller < than"), + 'expected7.4' => utf8_encode("Smaller < than"), + 'expected7.3' => utf8_encode("Smaller < than"), ], /** HTML **/ // break lines @@ -243,56 +257,65 @@ class ODFTest extends PHPUnit\Framework\TestCase 'to_convert' => "Break
line", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode("Breakline"), + 'expected7.4' => utf8_encode("Breakline"), + 'expected7.3' => utf8_encode("Breakline"), ], 16 => [ 'to_convert' => "Break
line", 'encode' => false, 'charset' => null, - 'expected' => utf8_encode("Breakline"), + 'expected7.4' => utf8_encode("Breakline"), + 'expected7.3' => utf8_encode("Breakline"), ], 17 => [ 'to_convert' => "Break
line", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode("Breakline"), + 'expected7.4' => utf8_encode("Breakline"), + 'expected7.3' => utf8_encode("Breakline"), ], 18 => [ 'to_convert' => "Break
line", 'encode' => false, 'charset' => null, - 'expected' => utf8_encode("Breakline"), + 'expected7.4' => utf8_encode("Breakline"), + 'expected7.3' => utf8_encode("Breakline"), ], // HTML tags 19 => [ 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", 'encode' => false, 'charset' => 'UTF-8', - 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', + 'expected7.4' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', + 'expected7.3' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', ], 20 => [ 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", 'encode' => true, 'charset' => 'UTF-8', - 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', + 'expected7.4' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', + 'expected7.3' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', ], 21 => [ 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", 'encode' => false, 'charset' => null, - 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), + 'expected7.4' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), + 'expected7.3' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), ], 22 => [ 'to_convert' => "text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), + 'expected7.4' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), + 'expected7.3' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), ], 23 => [ 'to_convert' => "text with intricatedtags", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode('text with intricatedtags'), + 'expected7.4' => utf8_encode('text with intricatedtags'), + 'expected7.3' => utf8_encode('text with intricatedtags'), ], // One can also pass html-encoded string to the method @@ -300,31 +323,36 @@ class ODFTest extends PHPUnit\Framework\TestCase 'to_convert' => 'One&two', 'encode' => true, 'charset' => null, - 'expected' => 'One&two' + 'expected7.4' => 'One&two', + 'expected7.3' => 'One&two' ], 25 => [ 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", 'encode' => false, 'charset' => 'UTF-8', - 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', + 'expected7.4' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', + 'expected7.3' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\'', ], 26 => [ 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", 'encode' => true, 'charset' => 'UTF-8', - 'expected' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', + 'expected7.4' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', + 'expected7.3' => 'text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l'', ], 27 => [ 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", 'encode' => false, 'charset' => null, - 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), + 'expected7.4' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), + 'expected7.3' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l\''), ], 28 => [ 'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>", 'encode' => true, 'charset' => null, - 'expected' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), + 'expected7.4' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), + 'expected7.3' => utf8_encode('text with strong, emphasis and underlined words with it@lic sp&ciàlchärs éè l''), ], // // TODO custom styles are not tested for now : the custom style have a custom ID based on time. Not random, but hard to mock or predict. generated in _replaceHtmlWithOdtTag() case 'span'. @@ -332,7 +360,7 @@ class ODFTest extends PHPUnit\Framework\TestCase // 'to_convert' => '123 trucmachin > truc < troc > tracbla bla', // 'encode' => true, // 'charset' => 'UTF-8', - // 'expected' => "123 trucmachin > truc < troc > tracbla bla'", + // 'expected7.4' => "123 trucmachin > truc < troc > tracbla bla'", // ], /* Tests that can evolve */ @@ -343,20 +371,23 @@ class ODFTest extends PHPUnit\Framework\TestCase 'to_convert' => '123 trucmachin > truc < troc > tracbla bla', 'encode' => true, 'charset' => null, - 'expected' => "123 trucmachin > truc < troc > tracbla bla", + 'expected7.4' => "123 trucmachin > truc < troc > tracbla bla", + 'expected7.3' => "123 trucmachin > truc < troc > tracbla bla", ], 30 => [ 'to_convert' => '123

Title

bla', 'encode' => true, 'charset' => null, - 'expected' => "123 Title bla", + 'expected7.4' => "123 Title bla", + 'expected7.3' => "123 Title bla", ], // HTML should not take \n into account, but only
. 31 => [ 'to_convert' => "text with strong text , a line\nbreak and underlined words with it@lic sp&ciàlchärs éè l'", 'encode' => false, 'charset' => 'UTF-8', - 'expected' => 'text with strong text , a line'."\n".'break and underlined words with it@lic sp&ciàlchärs éè l\'', + 'expected7.4' => 'text with strong text , a line'."\n".'break and underlined words with it@lic sp&ciàlchärs éè l\'', + 'expected7.3' => 'text with strong text , a line'."\n".'break and underlined words with it@lic sp&ciàlchärs éè l\'', ], ]; @@ -369,7 +400,11 @@ class ODFTest extends PHPUnit\Framework\TestCase } else { $res = $odf->convertVarToOdf($case['to_convert'], $case['encode']); } - $this->assertEquals($res, $case['expected']); + if (version_compare(phpversion(), '7.4.0', '>=' )) { + $this->assertEquals($res, $case['expected7.4']); + } else { + $this->assertEquals($res, $case['expected7.3']); + } } print __METHOD__." result=".$result."\n"; From 565e9f0c3d482ed601defcc42e4025231e97e8dd Mon Sep 17 00:00:00 2001 From: tnegre Date: Fri, 3 Feb 2023 15:33:50 +0100 Subject: [PATCH 09/64] Stickler fix --- test/phpunit/ODFTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/phpunit/ODFTest.php b/test/phpunit/ODFTest.php index 02c80dc9689..2bcc7bb0cb7 100644 --- a/test/phpunit/ODFTest.php +++ b/test/phpunit/ODFTest.php @@ -400,7 +400,7 @@ class ODFTest extends PHPUnit\Framework\TestCase } else { $res = $odf->convertVarToOdf($case['to_convert'], $case['encode']); } - if (version_compare(phpversion(), '7.4.0', '>=' )) { + if (version_compare(phpversion(), '7.4.0', '>=')) { $this->assertEquals($res, $case['expected7.4']); } else { $this->assertEquals($res, $case['expected7.3']); From fba22c8883c4440620c02167c3469772ec606c6f Mon Sep 17 00:00:00 2001 From: Eric Seigne Date: Tue, 14 Mar 2023 15:04:15 +0100 Subject: [PATCH 10/64] add setAsSelectUser --- htdocs/core/class/html.formsetup.class.php | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/htdocs/core/class/html.formsetup.class.php b/htdocs/core/class/html.formsetup.class.php index 40dec1870a4..26e892c1151 100644 --- a/htdocs/core/class/html.formsetup.class.php +++ b/htdocs/core/class/html.formsetup.class.php @@ -833,6 +833,8 @@ class FormSetupItem $out.= $this->generateInputFieldMultiSelect(); } elseif ($this->type == 'select') { $out.= $this->generateInputFieldSelect(); + } elseif ($this->type == 'selectUser') { + $out.= $this->generateInputFieldSelectUser(); } elseif ($this->type == 'textarea') { $out.= $this->generateInputFieldTextarea(); } elseif ($this->type== 'html') { @@ -992,6 +994,14 @@ class FormSetupItem return $this->form->selectarray($this->confKey, $this->fieldOptions, $this->fieldValue); } + /** + * @return string + */ + public function generateInputFieldSelectUser() + { + return $this->form->select_dolusers($this->fieldValue, $this->confKey); + } + /** * get the type : used for old module builder setup conf style conversion and tests * because this two class will quickly evolve it's important to not set or get directly $this->type (will be protected) so this method exist @@ -1066,6 +1076,8 @@ class FormSetupItem $out.= $this->generateOutputFieldMultiSelect(); } elseif ($this->type == 'select') { $out.= $this->generateOutputFieldSelect(); + } elseif ($this->type == 'selectUser') { + $out.= $this->generateOutputFieldSelectUser(); } elseif ($this->type== 'html') { $out.= $this->fieldValue; } elseif ($this->type== 'color') { @@ -1185,6 +1197,17 @@ class FormSetupItem return $outPut; } + /** + * @return string + */ + public function generateOutputFieldSelectUser() + { + $outPut = ''; + $user = new User($this->db); + $user->fetch($this->fieldValue); + $outPut = $user->firstname . " " . $user->lastname; + return $outPut; + } /* * METHODS FOR SETTING DISPLAY TYPE */ @@ -1335,4 +1358,16 @@ class FormSetupItem $this->type = 'select'; return $this; } + + /** + * Set type of input as a simple title + * no data to store + * @param array $fieldOptions A table of field options + * @return self + */ + public function setAsSelectUser() + { + $this->type = 'selectUser'; + return $this; + } } From 93cb4eb6bfce71a28209f98c23c5fe935bd7fd5c Mon Sep 17 00:00:00 2001 From: hystepik Date: Thu, 16 Mar 2023 14:51:15 +0100 Subject: [PATCH 11/64] New : uploadfile drag and drop on card --- htdocs/core/js/lib_foot.js.php | 43 +++++++++++++++++++++++++++++++ htdocs/core/lib/functions.lib.php | 5 ++-- htdocs/fourn/commande/card.php | 2 +- htdocs/theme/eldy/global.inc.php | 15 +++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/htdocs/core/js/lib_foot.js.php b/htdocs/core/js/lib_foot.js.php index 963e357199a..a6d48d10b8e 100644 --- a/htdocs/core/js/lib_foot.js.php +++ b/htdocs/core/js/lib_foot.js.php @@ -379,3 +379,46 @@ print ' }); }); '."\n"; + +// Code to manage the drag and drop file +//TODO: Find a way to display text over div +print "\n/* JS CODE TO ENABLE DRAG AND DROP OF FILE */\n"; +print ' + jQuery(document).ready(function() { + counterdragdrop = 0; + $(".cssDragDropArea").on("dragenter", function(ev) { + // Entering drop area. Highlight area + counterdragdrop++; + $(".cssDragDropArea").addClass("highlightDragDropArea"); + ev.preventDefault(); + }); + + $(".cssDragDropArea").on("dragleave", function(ev) { + // Going out of drop area. Remove Highlight + counterdragdrop--; + if (counterdragdrop === 0) { + $(".cssDragDropArea").removeClass("highlightDragDropArea"); + } + }); + + $(".cssDragDropArea").on("dragover", function(ev) { + ev.preventDefault(); + return false; + }); + + $(".cssDragDropArea").on("drop", function(e) { + console.log("Trigger event file droped"); + e.preventDefault(); + fd = new FormData(); + var dataTransfer = e.originalEvent.dataTransfer; + if(dataTransfer.files && dataTransfer.files.length){ + var droppedFiles = e.originalEvent.dataTransfer.files; + $.each(droppedFiles, function(index,file){ + fd.append("file",file,file.name) + }); + } + $(".cssDragDropArea").removeClass("highlightDragDropArea"); + counterdragdrop = 0; + }); + }); +'."\n"; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 4af0bbe610a..9a4ee8976ce 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1871,9 +1871,10 @@ function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0 * @param string $morecss More CSS on the link * @param int $limittoshow Limit number of tabs to show. Use 0 to use automatic default value. * @param string $moretabssuffix A suffix to use when you have several dol_get_fiche_head() in same page + * @param int $dragdropfile 0 (default) or 1. 1 enable a drop zone for file to be upload, 0 disable it * @return string */ -function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '') +function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0) { global $conf, $langs, $hookmanager; @@ -2039,7 +2040,7 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab } if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) { - $out .= "\n".'
'."\n"; + $out .= "\n".'
'."\n"; } $parameters = array('tabname' => $active, 'out' => $out); diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index f79c9fe49b4..5eb7f1a4539 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -1884,7 +1884,7 @@ if ($action == 'create') { $head = ordersupplier_prepare_head($object); $title = $langs->trans("SupplierOrder"); - print dol_get_fiche_head($head, 'card', $title, -1, 'order'); + print dol_get_fiche_head($head, 'card', $title, -1, 'order', 0, '', '', 0, '', 1); $formconfirm = ''; diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index cab0cb247ca..73a24a1671a 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -7591,7 +7591,22 @@ div.clipboardCPValue.hidewithsize { /* filter: blur(4px); */ } +/* ============================================================================== */ +/* For drag and drop feature */ +/* ============================================================================== */ +.cssDragDropArea{ + border: 2px rgba(123, 123, 123, .2) dashed !important; + padding: 10px !important; +} +.highlightDragDropArea{ + border: 2px #000 dashed !important; + background-color: #666 !important; +} +.highlightDragDropArea > *{ + opacity:0.5; + filter: blur(3px) grayscale(100%); +} /* ============================================================================== */ /* CSS style used for small screen */ /* ============================================================================== */ From 559d50a28364372e05d48ed3d7a7ce6e9600c40d Mon Sep 17 00:00:00 2001 From: hystepik Date: Thu, 16 Mar 2023 16:37:10 +0100 Subject: [PATCH 12/64] activate on fourn facture --- htdocs/fourn/commande/card.php | 2 +- htdocs/fourn/facture/card.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index 5eb7f1a4539..f79c9fe49b4 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -1884,7 +1884,7 @@ if ($action == 'create') { $head = ordersupplier_prepare_head($object); $title = $langs->trans("SupplierOrder"); - print dol_get_fiche_head($head, 'card', $title, -1, 'order', 0, '', '', 0, '', 1); + print dol_get_fiche_head($head, 'card', $title, -1, 'order'); $formconfirm = ''; diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 30e6ceda91e..730eb1d869e 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -2797,7 +2797,7 @@ if ($action == 'create') { $head = facturefourn_prepare_head($object); $titre = $langs->trans('SupplierInvoice'); - print dol_get_fiche_head($head, 'card', $titre, -1, 'supplier_invoice'); + print dol_get_fiche_head($head, 'card', $titre, -1, 'supplier_invoice', 0, '', '', 0, '', 1); $formconfirm = ''; From 4a1dabc3d712efda566520f22462de2ce483f54c Mon Sep 17 00:00:00 2001 From: hystepik Date: Fri, 17 Mar 2023 16:43:56 +0100 Subject: [PATCH 13/64] Upload works --- htdocs/core/js/lib_foot.js.php | 43 ------------------- htdocs/core/lib/files.lib.php | 71 +++++++++++++++++++++++++++++++ htdocs/core/lib/functions.lib.php | 4 +- 3 files changed, 74 insertions(+), 44 deletions(-) diff --git a/htdocs/core/js/lib_foot.js.php b/htdocs/core/js/lib_foot.js.php index a6d48d10b8e..963e357199a 100644 --- a/htdocs/core/js/lib_foot.js.php +++ b/htdocs/core/js/lib_foot.js.php @@ -379,46 +379,3 @@ print ' }); }); '."\n"; - -// Code to manage the drag and drop file -//TODO: Find a way to display text over div -print "\n/* JS CODE TO ENABLE DRAG AND DROP OF FILE */\n"; -print ' - jQuery(document).ready(function() { - counterdragdrop = 0; - $(".cssDragDropArea").on("dragenter", function(ev) { - // Entering drop area. Highlight area - counterdragdrop++; - $(".cssDragDropArea").addClass("highlightDragDropArea"); - ev.preventDefault(); - }); - - $(".cssDragDropArea").on("dragleave", function(ev) { - // Going out of drop area. Remove Highlight - counterdragdrop--; - if (counterdragdrop === 0) { - $(".cssDragDropArea").removeClass("highlightDragDropArea"); - } - }); - - $(".cssDragDropArea").on("dragover", function(ev) { - ev.preventDefault(); - return false; - }); - - $(".cssDragDropArea").on("drop", function(e) { - console.log("Trigger event file droped"); - e.preventDefault(); - fd = new FormData(); - var dataTransfer = e.originalEvent.dataTransfer; - if(dataTransfer.files && dataTransfer.files.length){ - var droppedFiles = e.originalEvent.dataTransfer.files; - $.each(droppedFiles, function(index,file){ - fd.append("file",file,file.name) - }); - } - $(".cssDragDropArea").removeClass("highlightDragDropArea"); - counterdragdrop = 0; - }); - }); -'."\n"; diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 60adcc64003..3e1c6892bbd 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -3316,3 +3316,74 @@ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathre return $file_list; } + +/** + * Function to manage the drag and drop file. + * We use global variable $object + * + * @return string Js script to display + */ +function dragAndDropFileUpload() +{ + global $object; + //TODO: Find a way to display text over div + $out = "\n"; + return $out; +} diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 9a4ee8976ce..92ceba99563 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2042,7 +2042,9 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) { $out .= "\n".'
'."\n"; } - + if (!empty($dragdropfile)) { + print dragAndDropFileUpload(); + } $parameters = array('tabname' => $active, 'out' => $out); $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead" if ($reshook > 0) { From 175747e345c053d0a067a039208964a4a359d9e7 Mon Sep 17 00:00:00 2001 From: Eric Seigne Date: Mon, 20 Mar 2023 00:32:15 +0100 Subject: [PATCH 14/64] copy same params than move --- htdocs/core/lib/files.lib.php | 76 +++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 60adcc64003..17c68de8e7d 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -707,12 +707,14 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask * @param string $destfile Destination file (can't be a directory) * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' * @param int $overwriteifexists Overwrite file if exists (1 by default) + * @param int $testvirus Do an antivirus test. Move is canceled if a virus is found. + * @param int $indexdatabase Index new file into database. * @return int <0 if error, 0 if nothing done (dest file already exists and overwriteifexists=0), >0 if OK * @see dol_delete_file() dolCopyDir() */ -function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) +function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1) { - global $conf; + global $conf, $db, $user; dol_syslog("files.lib.php::dol_copy srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." overwriteifexists=".$overwriteifexists); @@ -737,6 +739,17 @@ function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) dol_syslog("files.lib.php::dol_copy failed Permission denied to write into target directory ".$newdirdestfile, LOG_WARNING); return -2; } + + // Check virus + $testvirusarray = array(); + if ($testvirus) { + $testvirusarray = dolCheckVirus($srcfile); + if (count($testvirusarray)) { + dol_syslog("files.lib.php::dol_copy canceled because a virus was found into source file. we ignore the copy request.", LOG_WARNING); + return -3; + } + } + // Copy with overwriting if exists $result = @copy($newpathofsrcfile, $newpathofdestfile); //$result=copy($newpathofsrcfile, $newpathofdestfile); // To see errors, remove @ @@ -754,7 +767,64 @@ function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) dolChmod($newpathofdestfile, $newmask); - return 1; + if ($result && $indexdatabase) { + // Add entry into ecm database + $rel_filetocopyafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $newpathofdestfile); + if (!preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetocopyafter)) { // If not a tmp file + $rel_filetocopyafter = preg_replace('/^[\\/]/', '', $rel_filetocopyafter); + //var_dump($rel_filetorenamebefore.' - '.$rel_filetocopyafter);exit; + + dol_syslog("Try to copy also entries in database for: ".$rel_filetocopyafter, LOG_DEBUG); + include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + + $ecmfiletarget = new EcmFiles($db); + $resultecmtarget = $ecmfiletarget->fetch(0, '', $rel_filetocopyafter); + if ($resultecmtarget > 0) { // An entry for target name already exists for target, we delete it, a new one will be created. + dol_syslog("ECM dest file found, remove it", LOG_DEBUG); + $ecmfiletarget->delete($user); + } else { + dol_syslog("ECM dest file not found, create it", LOG_DEBUG); + } + + $ecmSrcfile = new EcmFiles($db); + $resultecm = $ecmSrcfile->fetch(0, '', $srcfile); + if ($resultecm) { + dol_syslog("Fetch src file ok", LOG_DEBUG); + } else { + dol_syslog("Fetch src file error", LOG_DEBUG); + } + + $ecmfile = new EcmFiles($db); + $filename = basename($rel_filetocopyafter); + $rel_dir = dirname($rel_filetocopyafter); + $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); + $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); + + $ecmfile->filepath = $rel_dir; + $ecmfile->filename = $filename; + $ecmfile->label = md5_file(dol_osencode($destfile)); // $destfile is a full path to file + $ecmfile->fullpath_orig = $srcfile; + $ecmfile->gen_or_uploaded = 'copy'; + $ecmfile->description = $ecmSrcfile->description; + $ecmfile->keywords = $ecmSrcfile->keywords; + $resultecm = $ecmfile->create($user); + if ($resultecm < 0) { + dol_syslog("Create ECM file ok", LOG_DEBUG); + setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); + } else { + dol_syslog("Create ECM file error", LOG_DEBUG); + setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); + } + + if ($resultecm > 0) { + $result = true; + } else { + $result = false; + } + } + } + + return $result; } /** From 8dd7a22482dcb0a5048dce045dad04881f87cd73 Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Mon, 20 Mar 2023 09:45:02 +0100 Subject: [PATCH 15/64] FIX limit after order in get objects in category --- htdocs/categories/class/categorie.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 786af013dc6..87c0888ed6f 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -848,10 +848,10 @@ class Categorie extends CommonObject if (($type == 'customer' || $type == 'supplier') && $user->socid > 0) { $sql .= " AND o.rowid = ".((int) $user->socid); } + $sql .= $this->db->order($sortfield, $sortorder); if ($limit > 0 || $offset > 0) { $sql .= $this->db->plimit($limit + 1, $offset); } - $sql .= $this->db->order($sortfield, $sortorder); dol_syslog(get_class($this)."::getObjectsInCateg", LOG_DEBUG); $resql = $this->db->query($sql); From 14fd90dbaddb4ae845f9461ea8e94a7d3554388f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 20 Mar 2023 14:20:35 +0100 Subject: [PATCH 16/64] Fix sign in llx_bank of amount_main_currency --- htdocs/install/mysql/migration/repair.sql | 21 +++++++++++++-------- htdocs/install/mysql/tables/llx_bank.sql | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index 737ee1bf511..4c6c4fc1117 100644 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -569,14 +569,19 @@ UPDATE llx_facturedet SET situation_percent = 100 WHERE situation_percent IS NUL DELETE FROM llx_rights_def WHERE module = 'hrm' AND perms = 'employee'; --- Sequence to fix the content of llx_bank.amount_main_currency --- Note: amount is amount in currency of bank account + +-- Sequence to fix the content of llx_bank.amount_main_currency (value was empty and should not for payment on bank account with a different currency so when amount_main_currency is different than amount) +-- Note: amount is amount in the currency of the bank account -- Note: pamount is always amount into the main currency --- Note: pmulticurrencyamount is in currency of invoice --- Note: amount_main_currency must be amount in main currency +-- Note: pmulticurrencyamount is in the currency of invoice +-- Note: amount_main_currency must be NULL or amount in main currency of company (we set it when the currency of the bank account differs from main currency) -- DROP TABLE tmp_bank; --- CREATE TABLE tmp_bank SELECT b.rowid, b.amount, p.rowid as pid, p.amount as pamount, p.multicurrency_amount as pmulticurrencyamount FROM llx_bank as b INNER JOIN llx_bank_url as bu ON bu.fk_bank=b.rowid AND bu.type = 'payment' INNER JOIN llx_paiement as p ON bu.url_id = p.rowid WHERE p.multicurrency_amount <> 0 AND p.multicurrency_amount <> p.amount; --- UPDATE llx_bank as b SET b.amount_main_currency = (SELECT tb.pamount FROM tmp_bank as tb WHERE tb.rowid = b.rowid) WHERE b.amount_main_currency IS NULL; +-- CREATE TABLE tmp_bank SELECT b.rowid, b.amount, p.rowid as pid, p.amount as pamount, p.multicurrency_amount as pmulticurrencyamount, b.datec FROM llx_bank as b INNER JOIN llx_bank_url as bu ON bu.fk_bank=b.rowid AND bu.type = 'payment' INNER JOIN llx_paiement as p ON bu.url_id = p.rowid WHERE p.multicurrency_amount <> 0 AND p.multicurrency_amount <> p.amount; +-- UPDATE llx_bank as b SET b.amount_main_currency = (SELECT tb.pamount FROM tmp_bank as tb WHERE tb.rowid = b.rowid) WHERE b.amount_main_currency IS NULL AND b.rowid IN (SELECT rowid FROM tmp_bank); -- DROP TABLE tmp_bank2; --- CREATE TABLE tmp_bank2 SELECT b.rowid, b.amount, p.rowid as pid, p.amount as pamount, p.multicurrency_amount as pmulticurrencyamount FROM llx_bank as b INNER JOIN llx_bank_url as bu ON bu.fk_bank=b.rowid AND bu.type = 'payment_supplier' INNER JOIN llx_paiementfourn as p ON bu.url_id = p.rowid WHERE p.multicurrency_amount <> 0 AND p.multicurrency_amount <> p.amount; --- UPDATE llx_bank as b SET b.amount_main_currency = (SELECT tb.pamount FROM tmp_bank2 as tb WHERE tb.rowid = b.rowid) WHERE b.amount_main_currency IS NULL; +-- CREATE TABLE tmp_bank2 SELECT b.rowid, b.amount, p.rowid as pid, - p.amount as pamount, - p.multicurrency_amount as pmulticurrencyamount, b.datec FROM llx_bank as b INNER JOIN llx_bank_url as bu ON bu.fk_bank=b.rowid AND bu.type = 'payment_supplier' INNER JOIN llx_paiementfourn as p ON bu.url_id = p.rowid WHERE p.multicurrency_amount <> 0 AND p.multicurrency_amount <> p.amount; +-- UPDATE llx_bank as b SET b.amount_main_currency = (SELECT tb.pamount FROM tmp_bank2 as tb WHERE tb.rowid = b.rowid) WHERE b.amount_main_currency IS NULL AND b.rowid IN (SELECT rowid FROM tmp_bank2); + +-- Sequence to fix the content of llx_bank.amount_main_currency (sign was wrong with some version) +-- UPDATE llx_bank as b SET b.amount_main_currency = -b.amount_main_currency WHERE b.amount IS NOT NULL AND b.amount_main_currency IS NOT NULL AND SIGN(b.amount_main_currency) <> SIGN(b.amount); + diff --git a/htdocs/install/mysql/tables/llx_bank.sql b/htdocs/install/mysql/tables/llx_bank.sql index d0a8e34790b..e5194cadc88 100644 --- a/htdocs/install/mysql/tables/llx_bank.sql +++ b/htdocs/install/mysql/tables/llx_bank.sql @@ -25,7 +25,7 @@ create table llx_bank datev date, -- date de valeur dateo date, -- date operation amount double(24,8) NOT NULL default 0, -- amount in the currency of the bank account - amount_main_currency double(24,8) NULL, -- amount in the main currency of the company + amount_main_currency double(24,8) NULL, -- amount in the main currency of the company when payment done in a bank account with a different currency label varchar(255), fk_account integer, fk_user_author integer, From 3f45699695d733e602db61ccd6daaadb7dc40654 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 20 Mar 2023 14:25:08 +0100 Subject: [PATCH 17/64] Prepare 16.0.5 --- ChangeLog | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f9e22813487..70e8cd5ad06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,51 @@ English Dolibarr ChangeLog ***** ChangeLog for 16.0.5 compared to 16.0.4 ***** -TODO +FIX: 16.0 propalestats Unknown column 'p.fk_soc' in 'on clause' +FIX: #23804 +FIX: #23860 +FIX: #23966 Error "Param dbt_keyfield is required but not defined" +FIX: accountancy lettering: better error management +FIX: accountancy lettering: correctly calculated number of lettering operations done +FIX: accountancy lettering: error management and prevention +FIX: accountancy lettering: prevent null results when fetching link with payments +FIX: Add missing hook on LibStatut +FIX: Add more context for selectForFormsListWhere Hook +FIX: attach file and send by mail in ticket +FIX: bad check on if in get_all_ways +FIX: Cannot import find type_fees with cgenericdic.class because it has id and not rowid +FIX: clicktodial backtopage +FIX: discount wasn't taken into account when adding a line in BOM +FIX: expense reports: error when selecting mileage fees expense type if MAIN_USE_EXPENSE_IK disabled +FIX: expense reports: JS error when selecting mileage fees expense type if MAIN_USE_EXPENSE_IK disabled +FIX: Extrafields in Notes to unify with orders or invoices. +FIX: fatal error on clicktodial backtopage +FIX: filter sql accounting account +FIX: Get data back on product update +FIX: Get data back when error on command create +FIX: label dictionary is used by barcode and member module +FIX: mandatory date for service didnt work for invoice +FIX: missing "authorid" for getNomUrl link right access +FIX: missing getEntity filter +FIX: vulnerability: missing protection on ajax public ticket page for valid email. +FIX: Missing right to edit service note when module product is disabled +FIX: multicompany compatibility +FIX: object $user is not defined +FIX: Object of class LDAP\Connection could not be converted to string +FIX: parse error and NAN +FIX: product ref fourn same size in supplier order/invoice as in product price fourn +FIX: Profit calculation on project preview tab. +FIX: Remove orphelan $this->db->rollback() in the function insertExtrafields() +FIX: request new password with "mc" and "twofactor" authentication +FIX: Resolve error message due to missing arguments +FIX: select for task in event card +FIX: several email sent to the same recipient when adding message from ticket +FIX: shipping list for external user +FIX: SQL error "unknown column p.fk_soc" because ANSI-92 joins take precedence over ANSI-89 joins +FIX: strato pdf +FIX: typos in getAttchments() $arrayobject +FIX: whitespaces +FIX: wrong url param name action ***** ChangeLog for 16.0.4 compared to 16.0.3 ***** From fab9d26254f2508fac53e01417df7362cdd179e8 Mon Sep 17 00:00:00 2001 From: hystepik Date: Mon, 20 Mar 2023 16:38:45 +0100 Subject: [PATCH 18/64] add of tyext when overing --- htdocs/core/lib/files.lib.php | 28 +++++++++++++++------------- htdocs/core/lib/functions.lib.php | 4 ++-- htdocs/langs/en_US/main.lang | 1 + htdocs/theme/eldy/global.inc.php | 19 ++++++++++++++++--- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 3e1c6892bbd..caeeb9c2976 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -3321,30 +3321,32 @@ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathre * Function to manage the drag and drop file. * We use global variable $object * - * @return string Js script to display + * @param string $htmlname The id of the component where we need to drag and drop + * @return string Js script to display */ -function dragAndDropFileUpload() +function dragAndDropFileUpload($htmlname) { - global $object; - //TODO: Find a way to display text over div - $out = "