diff --git a/core/spreadsheetbulkexport.class.inc.php b/core/spreadsheetbulkexport.class.inc.php index 03958fd52..fb9eeda25 100644 --- a/core/spreadsheetbulkexport.class.inc.php +++ b/core/spreadsheetbulkexport.class.inc.php @@ -52,7 +52,7 @@ class SpreadsheetBulkExport extends TabularBulkExport $oP->add('
'.Dict::S('Core:BulkExport:SpreadsheetOptions').''); $oP->add(''); $oP->add(''); - + $oP->add(''); - + $sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); $sDefaultChecked = ($sDateTimeFormat == (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; $sCustomChecked = ($sDateTimeFormat !== (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; - + $oP->add(''); - + $oP->add(''); $oP->add('
'); $sChecked = (utils::ReadParam('formatted_text', 1) == 1) ? ' checked ' : ''; $oP->add('

'.Dict::S('Core:BulkExport:TextFormat').'

'); @@ -60,11 +60,11 @@ class SpreadsheetBulkExport extends TabularBulkExport $oP->add('

'); $oP->add(''); $oP->add('
'); $oP->add('

'.Dict::S('Core:BulkExport:DateTimeFormat').'

'); $sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); @@ -73,23 +73,23 @@ class SpreadsheetBulkExport extends TabularBulkExport $sFormatInput = ''; $oP->add(''); $oP->add('
'); $oP->add('
'); $sJSTooltip = json_encode('
'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'
'); $oP->add_ready_script( -<<aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 1, true); - + $sDateFormatRadio = utils::ReadParam('spreadsheet_date_format_radio', ''); switch($sDateFormatRadio) { case 'default': - // Export from the UI => format = same as is the UI - $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); - break; - + // Export from the UI => format = same as is the UI + $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); + break; + case 'custom': - // Custom format specified from the UI - $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); - break; - + // Custom format specified from the UI + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + break; + default: - // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise - $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); + // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); } } - + protected function GetSampleData($oObj, $sAttCode) { if ($sAttCode != 'id') @@ -197,7 +197,7 @@ EOF { // Integration within MS-Excel web queries + HTTPS + IIS: // MS-IIS set these header values with no-cache... while Excel fails to do the job if using HTTPS - // Then the fix is to force the reset of header values Pragma and Cache-control + // Then the fix is to force the reset of header values Pragma and Cache-control $oPage->add_header("Pragma:", true); $oPage->add_header("Cache-control:", true); } @@ -252,14 +252,14 @@ EOF $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $this->OptimizeColumnLoad($oSet); - + $sExportDateTimeFormat = $this->aStatusInfo['date_format']; $bFormattedText = (array_key_exists('formatted_text', $this->aStatusInfo) ? $this->aStatusInfo['formatted_text'] : false); // Date & time formats $oDateTimeFormat = new DateTimeFormat($sExportDateTimeFormat); $oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat()); $oTimeFormat = new DateTimeFormat($oDateTimeFormat->ToTimeFormat()); - + $iCount = 0; $sData = ''; $iPreviousTimeLimit = ini_get('max_execution_time'); @@ -281,69 +281,69 @@ EOF $sData .= ""; continue; } - + switch($sAttCode) { case 'id': - $sField = $oObj->GetKey(); - $sData .= "$sField"; - break; + $sField = $oObj->GetKey(); + $sData .= "$sField"; + break; default: - $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); - $oFinalAttDef = $oAttDef->GetFinalAttDef(); - if (get_class($oFinalAttDef) == 'AttributeDateTime') - { - // Split the date and time in two columns - $sDate = $oDateFormat->Format($oObj->Get($sAttCode)); - $sTime = $oTimeFormat->Format($oObj->Get($sAttCode)); - $sData .= "$sDate"; - $sData .= "$sTime"; - } - else if (get_class($oFinalAttDef) == 'AttributeDate') - { - $sDate = $oDateFormat->Format($oObj->Get($sAttCode)); - $sData .= "$sDate"; - } - else if($oAttDef instanceof AttributeCaseLog) - { - $rawValue = $oObj->Get($sAttCode); - $sField = str_replace("\n", "
", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8')); - // Trick for Excel: treat the content as text even if it begins with an equal sign - $sData .= "$sField"; - } - elseif ($oAttDef instanceof AttributeText) - { - if ($bFormattedText) + $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); + $oFinalAttDef = $oAttDef->GetFinalAttDef(); + if (get_class($oFinalAttDef) == 'AttributeDateTime') { - // Replace paragraphs (...

, etc) by line breaks (
) since Excel (pre-2016) splits the cells when there is a paragraph - $sField = static::HtmlToSpreadsheet($oObj->GetAsHTML($sAttCode)); + // Split the date and time in two columns + $sDate = $oDateFormat->Format($oObj->Get($sAttCode)); + $sTime = $oTimeFormat->Format($oObj->Get($sAttCode)); + $sData .= "$sDate"; + $sData .= "$sTime"; + } + else if (get_class($oFinalAttDef) == 'AttributeDate') + { + $sDate = $oDateFormat->Format($oObj->Get($sAttCode)); + $sData .= "$sDate"; + } + else if($oAttDef instanceof AttributeCaseLog) + { + $rawValue = $oObj->Get($sAttCode); + $sField = str_replace("\n", "
", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8')); + // Trick for Excel: treat the content as text even if it begins with an equal sign + $sData .= "$sField"; + } + elseif ($oAttDef instanceof AttributeText) + { + if ($bFormattedText) + { + // Replace paragraphs (...

, etc) by line breaks (
) since Excel (pre-2016) splits the cells when there is a paragraph + $sField = static::HtmlToSpreadsheet($oObj->GetAsHTML($sAttCode)); + } + else + { + // Convert to plain text + $sField = utils::HtmlToText($oObj->GetAsHTML($sAttCode)); + } + $sData .= "$sField"; + } + else if($oAttDef instanceof AttributeString) + { + $sField = $oObj->GetAsHTML($sAttCode, $this->bLocalizeOutput); + $sData .= "$sField"; } else { - // Convert to plain text - $sField = utils::HtmlToText($oObj->GetAsHTML($sAttCode)); + $rawValue = $oObj->Get($sAttCode); + if ($this->bLocalizeOutput) + { + $sField = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8'); + } + else + { + $sField = htmlentities($rawValue, ENT_QUOTES, 'UTF-8'); + } + $sData .= "$sField"; } - $sData .= "$sField"; - } - else if($oAttDef instanceof AttributeString) - { - $sField = $oObj->GetAsHTML($sAttCode, $this->bLocalizeOutput); - $sData .= "$sField"; - } - else - { - $rawValue = $oObj->Get($sAttCode); - if ($this->bLocalizeOutput) - { - $sField = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8'); - } - else - { - $sField = htmlentities($rawValue, ENT_QUOTES, 'UTF-8'); - } - $sData .= "$sField"; - } } } @@ -391,7 +391,7 @@ EOF { return 'html'; } - + /** * Cleanup all markup displayed as line breaks (except
tags) since this * causes Excel (pre-2016) to generate extra lines in the table, thus breaking @@ -402,28 +402,40 @@ EOF */ public static function HtmlToSpreadsheet($sHtml) { + if (trim(strip_tags($sHtml)) === '') + { + // Display this value as an empty cell in the table + return ' '; + } // The tags listed here are a subset of the whitelist defined in HTMLDOMSanitizer - // Tags causing a visual "line break" in the displayed page (i.e. display: block) => to be replaced by a followed by a
+ // Tags causing a visual "line break" in the displayed page (i.e. display: block) are to be replaced by a followed by a
+ // in order to preserve any inline style/attribute of the removed tag $aTagsToReplace = array( - 'pre', 'div', 'p', 'hr', 'center', 'h1', 'h2', 'h3', 'h4', 'li', 'fieldset', 'legend', 'nav', 'section', 'tr', 'caption', + 'pre', 'div', 'p', 'hr', 'center', 'h1', 'h2', 'h3', 'h4', 'li', 'fieldset', 'legend', 'nav', 'section', 'tr', 'caption', ); // Tags to completely remove from the markup $aTagsToRemove = array( 'table', 'thead', 'tbody', 'ul', 'ol', 'td', 'th', ); + + // Remove the englobing
...
to prevent an extra line break + $sHtml = preg_replace('|^
(.*)
$|s', '$1', $sHtml); // Must use the "s" (. matches newline) modifier foreach($aTagsToReplace as $sTag) { - $sHtml = preg_replace("|<{$sTag} ?([^>]*)>|i", '', $sHtml); + $sHtml = preg_replace("|<{$sTag} ?([^>]*)>|is", '', $sHtml); $sHtml = preg_replace("||i", '
', $sHtml); } - + foreach($aTagsToRemove as $sTag) { - $sHtml = preg_replace("|<{$sTag} ?([^>]*)>|i", '', $sHtml); + $sHtml = preg_replace("|<{$sTag} ?([^>]*)>|is", '', $sHtml); $sHtml = preg_replace("||i", '', $sHtml); } - + + // Remove any trailing
, if any, to prevent an extra line break + $sHtml = preg_replace("|
$|", '', $sHtml); + return $sHtml; } }