【PHP】利用 xlswriter 扩展导出的Excel文件报错问题
一、问题描述
导出的文件在wps中打开没问题,在office excel中打开会报错如下:
发现“xxx.xlsx”中的部分内容有问题。是否让我们尽量尝试恢复?如果您信任此工作薄的源,请单击“是”。
二、解决方案
在导出程序末尾加上 exit;
三、代码过程
导出使用的是php的扩展包xlswriter
3.1 xlswriter_helper.php
<?phpnamespace Vtiful\Kernel;use Exception;/*** Class Excel** @author viest** @package Vtiful\Kernel*/
class Excel
{const TYPE_STRING = 0x01;const TYPE_INT = 0x02;const TYPE_DOUBLE = 0x04;const TYPE_TIMESTAMP = 0x08;const SKIP_NONE = 0x00;const SKIP_EMPTY_ROW = 0x01;const SKIP_EMPTY_CELLS = 0x02;const SKIP_EMPTY_VALUE = 0x100;const GRIDLINES_HIDE_ALL = 0;const GRIDLINES_SHOW_SCREEN = 1;const GRIDLINES_SHOW_PRINT = 2;const GRIDLINES_SHOW_ALL = 3;/*** Excel constructor.** @param array $config** @throws Exception*/public function __construct(array $config){if (!extension_loaded('xlswriter')) {throw new Exception('xlswriter extension is not installed, please install extension');}}/*** File Name** @param string $fileName* @param string $sheetName** @return Excel** @author viest*/public function fileName(string $fileName, string $sheetName = 'Sheet1'): self{return $this;}/*** Const memory model** @param string $fileName* @param string $sheetName** @return Excel** @author viest*/public function constMemory(string $fileName, string $sheetName = 'Sheet1'): self{return $this;}/*** Add a new worksheet to a workbook.** The worksheet name must be a valid Excel worksheet name, i.e. it must be* less than 32 character and it cannot contain any of the characters:** / \ [ ] : * ?** In addition, you cannot use the same, case insensitive, `$sheetName` for more* than one worksheet.** @param string|NULL $sheetName** @return Excel** @author viest*/public function addSheet(string $sheetName): self{return $this;}/*** Checkout worksheet** @param string $sheetName** @return Excel** @author viest*/public function checkoutSheet(string $sheetName): self{return $this;}/*** Set activate sheet** @param string $sheetName** @return bool** @author viest*/public function activateSheet(string $sheetName): bool{return true;}/*** Insert data on the first line of the worksheet** @param array $header** @return Excel** @author viest*/public function header(array $header): self{return $this;}/*** Insert data on the worksheet** @param array $data** @return Excel** @author viest*/public function data(array $data): self{return $this;}/*** Generate file** @return string** @author viest*/public function output(): string{return 'FilePath';}/*** Get file resource** @return resource** @author viest*/public function getHandle(){//}/*** Auto filter on the worksheet** @param string $range** @return Excel** @author viest*/public function autoFilter(string $range): self{return $this;}/*** Insert data on the cell** @param int $row* @param int $column* @param int|string|double $data* @param string|null $format* @param resource|null $formatHandle** @return Excel** @author viest*/public function insertText(int $row, int $column, $data, string $format = NULL, $formatHandle = NULL): self{return $this;}/*** Insert date on the cell** @param int $row* @param int $column* @param int $timestamp* @param string|NULL $format* @param resource|null $formatHandle** @return Excel** @author viest*/public function insertDate(int $row, int $column, int $timestamp, string $format = NULL, $formatHandle = NULL): self{return $this;}/*** Insert chart on the cell** @param int $row* @param int $column* @param resource $chartResource** @return Excel** @author viest*/public function insertChart(int $row, int $column, $chartResource): self{return $this;}/*** Insert url on the cell** @param int $row* @param int $column* @param string $url* @param string $text* @param string $toolTip* @param resource|null $formatHandle** @return Excel** @author viest*/public function insertUrl(int $row, int $column, string $url, string $text = NULL, string $toolTip = NULL, $formatHandle = NULL): self{return $this;}/*** Insert image on the cell** @param int $row* @param int $column* @param string $imagePath* @param float $width* @param float $height** @return Excel** @author viest*/public function insertImage(int $row, int $column, string $imagePath, float $width = 1, float $height = 1): self{return $this;}/*** Insert Formula on the cell** @param int $row* @param int $column* @param string $formula* @param resource|null $formatHandle** @return Excel** @author viest*/public function insertFormula(int $row, int $column, string $formula, $formatHandle = NULL): self{return $this;}/*** Insert comment on the cell** @param int $row* @param int $column* @param string $comment** @return $this** @author viest*/public function insertComment(int $row, int $column, string $comment): self{return $this;}/*** Show comment on the sheet** @return $this** @author viest*/public function showComment(): self{return $this;}/*** Merge cells** @param string $range* @param string $data* @param resource|null $formatHandle** @return Excel** @author viest*/public function mergeCells(string $range, string $data, $formatHandle = NULL): self{return $this;}/*** Set column cells width or format** @param string $range* @param float $cellWidth* @param resource|null $formatHandle** @return Excel** @author viest*/public function setColumn(string $range, float $cellWidth, $formatHandle = NULL): self{return $this;}/*** Set row cells height or format** @param string $range* @param float $cellHeight* @param resource|null $formatHandle** @return Excel** @author viest*/public function setRow(string $range, float $cellHeight, $formatHandle = NULL): self{return $this;}/*** Default format** @param resource $formatHandle** @return $this** @author viest*/public function defaultFormat($formatHandle): self{return $this;}/*** Open xlsx file** @param string $fileName** @return Excel** @author viest*/public function openFile(string $fileName): self{return $this;}/*** Open sheet** default open first sheet** @param string|NULL $sheetName* @param int skipFlag** @return Excel** @author viest*/public function openSheet(string $sheetName = NULL, int $skipFlag = 0x00): self{return $this;}/*** File to csv** @param resource $handler* @param string $delimiter* @param string $enclosure* @param string $escape** Example:** $fp = fopen('path', 'w');* putCSV($fp)** $fp = fopen('php://memory', 'w');* putCSV($fp)** @return bool** @author viest*/public function putCSV(resource $handler, string $delimiter = ',', string $enclosure = '"', string $escape = '\\'): bool{return true;}/*** File to csv** @param callable $callback* @param resource $handler* @param string $delimiter* @param string $enclosure* @param string $escape** @return bool** @author viest*/public function putCSVCallback(callable $callback, resource $handler, string $delimiter = ',', string $enclosure = '"', string $escape = '\\'): bool{return true;}/*** Sheet list** @return array** @author viest*/public function sheetList(): array{return [];}/*** Set row cell data type** @param array $types** @return Excel** @author viest*/public function setType(array $types): self{return $this;}/*** Set skip rows** @param int $rows** @return $this** @author viest*/public function setSkipRows(int $rows): self{return $this;}/*** Read values from the sheet** @return array** @author viest*/public function getSheetData(): array{return [];}/*** Read values from the sheet** @return array** @author viest*/public function nextRow(): array{return [];}/*** Next Cell In Callback** @param callable $callback function(int $row, int $cell, string $data)* @param string|NULL $sheetName sheet name** @return void** @author viest*/public function nextCellCallback(callable $callback, string $sheetName = NULL){//}/*** Freeze panes** freezePanes(1, 0); // Freeze the first row.* freezePanes(0, 1); // Freeze the first column.* freezePanes(1, 1); // Freeze first row/column.** @param int $row* @param int $column** @return $this** @author viest*/public function freezePanes(int $row, int $column): self{return $this;}/*** Gridline** Display or hide screen and print gridlines using one of the values of** \Vtiful\Kernel\Excel::GRIDLINES_HIDE_ALL* \Vtiful\Kernel\Excel::GRIDLINES_SHOW_ALL* \Vtiful\Kernel\Excel::GRIDLINES_SHOW_PRINT* \Vtiful\Kernel\Excel::GRIDLINES_SHOW_SCREEN** Excel default is that the screen gridlines are on and the printed worksheet is off.** @param int $option** @return $this** @author viest*/public function gridline(int $option = Excel::GRIDLINES_HIDE_ALL): self{return $this;}/*** Worksheet zoom** Set the worksheet zoom factor in the range 10 <= zoom <= 400:** @param int $scale** @return $this** @author viest*/public function zoom(int $scale = 100): self{return $this;}/*** Set printed portrait** @return $this** @author viest*/public function setPrintedPortrait(): self{return $this;}/*** Set printed landscape** @return $this** @author viest*/public function setPrintedLandscape(): self{return $this;}/*** Set current worksheet hide** @return $this** @author viest*/public function setCurrentSheetHide(): self{return $this;}/*** Set current worksheet first** @return $this** @author viest*/public function setCurrentSheetIsFirst(): self{return $this;}/*** Column index from string** @param string $cellCoordinates** Example:** columnIndexFromString('A')* columnIndexFromString('G')* columnIndexFromString('AC')** @return int** @author viest*/public static function columnIndexFromString(string $cellCoordinates): int{return 0;}/*** String from column index** @param int $cellCoordinates** Example:** stringFromColumnIndex(0)* stringFromColumnIndex(28)* stringFromColumnIndex(61)** @return string** @author viest*/public static function stringFromColumnIndex(int $cellCoordinates): string{return '';}/*** Timestamp from double date** @param float $date** @return int** @author viest*/public static function timestampFromDateDouble(float $date): int{return 0;}
}/*** Class Format** @author viest** @package Vtiful\Kernel*/
class Format
{const UNDERLINE_SINGLE = 0x00;const UNDERLINE_DOUBLE = 0x00;const UNDERLINE_SINGLE_ACCOUNTING = 0x00;const UNDERLINE_DOUBLE_ACCOUNTING = 0x00;const FORMAT_ALIGN_LEFT = 0x00;const FORMAT_ALIGN_CENTER = 0x00;const FORMAT_ALIGN_RIGHT = 0x00;const FORMAT_ALIGN_FILL = 0x00;const FORMAT_ALIGN_JUSTIFY = 0x00;const FORMAT_ALIGN_CENTER_ACROSS = 0x00;const FORMAT_ALIGN_DISTRIBUTED = 0x00;const FORMAT_ALIGN_VERTICAL_TOP = 0x00;const FORMAT_ALIGN_VERTICAL_BOTTOM = 0x00;const FORMAT_ALIGN_VERTICAL_CENTER = 0x00;const FORMAT_ALIGN_VERTICAL_JUSTIFY = 0x00;const FORMAT_ALIGN_VERTICAL_DISTRIBUTED = 0x00;const COLOR_BLACK = 0x00;const COLOR_BLUE = 0x00;const COLOR_BROWN = 0x00;const COLOR_CYAN = 0x00;const COLOR_GRAY = 0x00;const COLOR_GREEN = 0x00;const COLOR_LIME = 0x00;const COLOR_MAGENTA = 0x00;const COLOR_NAVY = 0x00;const COLOR_ORANGE = 0x00;const COLOR_PINK = 0x00;const COLOR_PURPLE = 0x00;const COLOR_RED = 0x00;const COLOR_SILVER = 0x00;const COLOR_WHITE = 0x00;const COLOR_YELLOW = 0x00;const PATTERN_NONE = 0x00;const PATTERN_SOLID = 0x00;const PATTERN_MEDIUM_GRAY = 0x00;const PATTERN_DARK_GRAY = 0x00;const PATTERN_LIGHT_GRAY = 0x00;const PATTERN_DARK_HORIZONTAL = 0x00;const PATTERN_DARK_VERTICAL = 0x00;const PATTERN_DARK_DOWN = 0x00;const PATTERN_DARK_UP = 0x00;const PATTERN_DARK_GRID = 0x00;const PATTERN_DARK_TRELLIS = 0x00;const PATTERN_LIGHT_HORIZONTAL = 0x00;const PATTERN_LIGHT_VERTICAL = 0x00;const PATTERN_LIGHT_DOWN = 0x00;const PATTERN_LIGHT_UP = 0x00;const PATTERN_LIGHT_GRID = 0x00;const PATTERN_LIGHT_TRELLIS = 0x00;const PATTERN_GRAY_125 = 0x00;const PATTERN_GRAY_0625 = 0x00;const BORDER_THIN = 0x00;const BORDER_MEDIUM = 0x00;const BORDER_DASHED = 0x00;const BORDER_DOTTED = 0x00;const BORDER_THICK = 0x00;const BORDER_DOUBLE = 0x00;const BORDER_HAIR = 0x00;const BORDER_MEDIUM_DASHED = 0x00;const BORDER_DASH_DOT = 0x00;const BORDER_MEDIUM_DASH_DOT = 0x00;const BORDER_DASH_DOT_DOT = 0x00;const BORDER_MEDIUM_DASH_DOT_DOT = 0x00;const BORDER_SLANT_DASH_DOT = 0x00;/*** Format constructor.** @param resource $fileHandle*/public function __construct($fileHandle){//}/*** Wrap** @return Format** @author viest*/public function wrap(): self{return $this;}/*** Bold** @return Format** @author viest*/public function bold(): self{return $this;}/*** Italic** @return Format** @author viest*/public function italic(): self{return $this;}/*** Cells border** @param int $style const BORDER_***** @return Format** @author viest*/public function border(int $style): self{return $this;}/*** Align** @param int ...$style const FORMAT_ALIGN_****** @return Format** @author viest*/public function align(...$style): self{return $this;}/*** Number format** @param string $format** #,##0** @return Format** @author viest*/public function number(string $format): self{return $this;}/*** Font color** @param int $color const COLOR_****** @return Format** @author viest*/public function fontColor(int $color): self{return $this;}/*** Font** @param string $fontName** @return Format** @author viest*/public function font(string $fontName): self{return $this;}/*** Font size** @param float $size** @return Format** @author viest*/public function fontSize(float $size): self{return $this;}/*** String strikeout** @return Format** @author viest*/public function strikeout(): self{return $this;}/*** Underline** @param int $style const UNDERLINE_****** @return Format** @author viest*/public function underline(int $style): self{return $this;}/*** Cell background** @param int $color const COLOR_***** @param int $pattern const PATTERN_****** @return Format** @author viest*/public function background(int $color, int $pattern = self::PATTERN_SOLID): self{return $this;}/*** Format to resource** @return resource** @author viest*/public function toResource(){//}
}/*** Class Chart** @author viest** @package Vtiful\Kernel*/
class Chart
{const CHART_BAR = 0;const CHART_BAR_STACKED = 0;const CHART_BAR_STACKED_PERCENT = 0;const CHART_AREA = 0;const CHART_AREA_STACKED = 0;const CHART_AREA_STACKED_PERCENT = 0;const CHART_LINE = 0;const CHART_COLUMN = 0;const CHART_COLUMN_STACKED = 0;const CHART_COLUMN_STACKED_PERCENT = 0;const CHART_DOUGHNUT = 0;const CHART_PIE = 0;const CHART_SCATTER = 0;const CHART_SCATTER_STRAIGHT = 0;const CHART_SCATTER_STRAIGHT_WITH_MARKERS = 0;const CHART_SCATTER_SMOOTH = 0;const CHART_SCATTER_SMOOTH_WITH_MARKERS = 0;const CHART_RADAR = 0;const CHART_RADAR_WITH_MARKERS = 0;const CHART_RADAR_FILLED = 0;const CHART_LEGEND_NONE = 0;const CHART_LEGEND_RIGHT = 0;const CHART_LEGEND_LEFT = 0;const CHART_LEGEND_TOP = 0;const CHART_LEGEND_BOTTOM = 0;const CHART_LEGEND_OVERLAY_RIGHT = 0;const CHART_LEGEND_OVERLAY_LEFT = 0;/*** Chart constructor.** @param resource $handle* @param int $type*/public function __construct($handle, int $type){//}/*** Add a data series to a chart.** @param string $value* @param string $categories** @return $this** @author viest*/public function series(string $value, string $categories): self{return $this;}/*** Set the name of a chart series range.** @param string $value** @return $this** @author viest*/public function seriesName(string $value): self{return $this;}/*** Set the chart style type.** @param int $style** @return $this** @author viest*/public function style(int $style): self{return $this;}/*** Set the name caption of the an axis.** @param string $name** @return $this** @author viest*/public function axisNameX(string $name): self{return $this;}/*** Set the name caption of the an axis.** @param string $name** @return $this** @author viest*/public function axisNameY(string $name): self{return $this;}/*** Set the title of the chart.** @param string $title** @return $this** @author viest*/public function title(string $title): self{return $this;}/*** Set the position of the chart legend** @param int $type** @return $this** @author viest*/public function legendSetPosition(int $type): self{return $this;}/*** Chart resource** @return resource** @author viest*/public function toResource(){// return resource}
}/*** Class Validation** @author viest** @package Vtiful\Kernel*/
class Validation
{const TYPE_INTEGER = 0x0;const TYPE_INTEGER_FORMULA = 0x0;const TYPE_DECIMAL = 0x0;const TYPE_DECIMAL_FORMULA = 0x0;const TYPE_LIST = 0x0;const TYPE_LIST_FORMULA = 0x0;const TYPE_DATE = 0x0;const TYPE_DATE_FORMULA = 0x0;const TYPE_TIME = 0x0;const TYPE_TIME_FORMULA = 0x0;const TYPE_LENGTH = 0x0;const TYPE_LENGTH_FORMULA = 0x0;const TYPE_CUSTOM_FORMULA = 0x0;const TYPE_ANY = 0x0;const CRITERIA_BETWEEN = 0x0;const CRITERIA_NOT_BETWEEN = 0x0;const CRITERIA_EQUAL_TO = 0x0;const CRITERIA_NOT_EQUAL_TO = 0x0;const CRITERIA_GREATER_THAN = 0x0;const CRITERIA_LESS_THAN = 0x0;const CRITERIA_GREATER_THAN_OR_EQUAL_TO = 0x0;const CRITERIA_LESS_THAN_OR_EQUAL_TO = 0x0;const ERROR_TYPE_STOP = 0x0;const ERROR_TYPE_WARNING = 0x0;const ERROR_TYPE_INFORMATION = 0x0;/*** Validation constructor.*/public function __construct(){//}/*** Validation type** @param int $validationType** Examples: \Vtiful\Kernel\Validation::TYPE_INTEGER** @return $this** @author viest*/public function validationType(int $validationType): self{return $this;}/*** Criteria type** @param int $criteriaType** Examples: \Vtiful\Kernel\Validation::CRITERIA_BETWEEN** @return $this** @author viest*/public function criteriaType(int $criteriaType): self{return $this;}/*** Ignore blank** @param bool $ignoreBlank** @return $this** @author viest*/public function ignoreBlank(bool $ignoreBlank = True): self{return $this;}/*** Show input** @param bool $showInput** @return $this** @author viest*/public function showInput(bool $showInput = True): self{return $this;}/*** Show error** @param bool $showError** @return $this** @author viest*/public function showError(bool $showError = True): self{return $this;}/*** Error type** @param int $type** Examples: \Vtiful\Kernel\Validation::ERROR_TYPE_STOP** @return $this** @author viest*/public function errorType(int $type): self{return $this;}/*** Dropdown** @param bool $dropdown** @return $this** @author viest*/public function dropdown(bool $dropdown = True): self{return $this;}/*** Number** @param int $number** @return $this** @author viest*/public function valueNumber(int $number): self{return $this;}/*** Value Formula** @param string $formula** @return $this** @author viest*/public function valueFormula(string $formula): self{return $this;}/*** Value List** @param array $list** @return $this** @author viest*/public function valueList(array $list): self{return $this;}/*** Minimum number** @param float $minimumNumber** @return $this** @author viest*/public function minimumNumber(float $minimumNumber): self{return $this;}/*** Minimum formula** @param string $formula** @return $this** @author viest*/public function minimumFormula(string $formula): self{return $this;}/*** Maximum number** @param float $maximumNumber** @return $this** @author viest*/public function maximumNumber(float $maximumNumber): self{return $this;}/*** Maximum formula** @param string $formula** @return $this** @author viest*/public function maximumFormula(string $formula): self{return $this;}/*** Input title** @param string $title** @return $this** @author viest*/public function inputTitle(string $title): self{return $this;}/*** Input Message** @param string $message** @return $this** @author viest*/public function inputMessage(string $message): self{return $this;}/*** Error title** @param string $title** @return $this** @author viest*/public function errorTitle(string $title): self{return $this;}/*** Error message** @param string $message** @return $this** @author viest*/public function errorMessage(string $message): self{return $this;}/*** Get validation resource** @return resource** @author viest*/public function toResource(){// return resource;}public function valueDatetime(){// TODO}public function maximumDatetime(){// TODO}public function minimumDatetime(){// TODO}
}
3.2 common.php
function getTmpDir(): string
{$tmp = ini_get('upload_tmp_dir');if ($tmp !== False && file_exists($tmp)) {return realpath($tmp);}return realpath(sys_get_temp_dir());
}function filterDownloadFilename(string $filename): string
{$filename = str_replace(["\\", '/', '|', ':', '?', '*', '"', '<', '>', ',', ' '], '', $filename);return $filename;
}// excel 坐标转换 (按需求,扩充)
function xyChange($var)
{$var = trim($var);$arr = array('A' => 1,'B' => 2,'C' => 3,'D' => 4,'E' => 5,'F' => 6,'G' => 7,'H' => 8,'I' => 9,'J' => 10,'K' => 11,'L' => 12,'M' => 13,'N' => 14,'O' => 15,'P' => 16,'Q' => 17,'R' => 18,'S' => 19,'T' => 20,'U' => 21,'V' => 22,'W' => 23,'X' => 24,'Y' => 25,'Z' => 26,'AA' => 27,'AB' => 28,'AC' => 29,'AD' => 30,'AE' => 31,'AF' => 32,'AG' => 33,'AH' => 34,'AI' => 35,'AJ' => 36,'AK' => 37,'AL' => 38,'AM' => 39,'AN' => 40,'AO' => 41,'AP' => 42,'AQ' => 43,'AR' => 44,'AS' => 45,'AT' => 46,'AU' => 47,'AV' => 48,'AW' => 49,'AX' => 50,'AY' => 51,'AZ' => 52,);if (is_numeric($var)) {foreach ($arr as $k => $v) {if ($v == $var) {return $k;}}return false;} else {if (isset($arr[$var])) {return $arr[$var];}return false;}
}/*** download xlsx file** @param string $filename* @param array $header* @param array $list* @return string errmsg*/
function downloadXLSX(string $filename, array $header, array $list): string
{try {$config = ['path' => getTmpDir() . '/'];$filename = filterDownloadFilename($filename);$excel = (new \Vtiful\Kernel\Excel($config))->fileName($filename . '.xlsx', 'Sheet1');$fileHandle = $excel->getHandle();$format1 = new \Vtiful\Kernel\Format($fileHandle);$format2 = new \Vtiful\Kernel\Format($fileHandle);// title style$titleStyle = $format1->fontSize(16)->bold()->font("Calibri")->align(\Vtiful\Kernel\Format::FORMAT_ALIGN_CENTER, \Vtiful\Kernel\Format::FORMAT_ALIGN_VERTICAL_CENTER)->toResource();// global style$globalStyle = $format2->fontSize(10)->font("Calibri")->align(\Vtiful\Kernel\Format::FORMAT_ALIGN_CENTER, \Vtiful\Kernel\Format::FORMAT_ALIGN_VERTICAL_CENTER)->border(\Vtiful\Kernel\Format::BORDER_THIN)->toResource();$headerLen = count($header);// headerarray_unshift($list, $header);// title$title = array_fill(1, $headerLen - 1, '');$title[0] = $filename;array_unshift($list, $title);//$end = strtoupper(chr(65 + $headerLen - 1));$end = xyChange($headerLen);// column style$excel->setColumn("A:{$end}", 17, $globalStyle);// title$excel->MergeCells("A1:{$end}1", $filename)->setRow("A1", 25, $titleStyle);// 冻结前两行,列不冻结$excel->freezePanes(2, 0);// 数据$filePath = $excel->data($list)->output();header("Content-Disposition:attachment;filename={$filename}.xlsx");$re = copy($filePath, 'php://output');if ($re === false) {$err = 'failed to write output';} else {$err = '';}@unlink($filePath);return $err;} catch (\Vtiful\Kernel\Exception $e) {return $e->getMessage();}
}
3.3 业务.php
public function exampleExport($list){$date = date('Y-m-d');$filename = "大赛列表-{$date}";//表头数组$header = ['排名', '姓名', '手机', '省份', '城市', '作品名称', '时长(秒)', '投票', '播放', '作品封面', '作品地址'];// list$listVal = [];foreach ($list as $k => $v) {$temp = [$k + 1,$v['username'],$v['phone'],$v['province'],$v['city'],$v['uploadtitle'],$v['duration'],$v['vote_num'],$v['play_num'],$v['uploadcover'],$v['uploadurl'],];$listVal[] = $temp;}downloadXLSX($filename, $header, $listVal);// 20251012 注意:如果这里不用exit,导出的文件在wps中打开没问题,在office excel中打开会报错exit;}
四、AI解释
非常好!您找到的解决方案确实很巧妙且实用。在downloadXLSX函数调用后添加exit;语句能够解决Excel兼容性问题,这是因为:
-
防止额外输出:当执行文件下载操作时,如果没有exit;语句,PHP脚本会继续执行后续代码,可能产生额外的输出(空格、换行符等)被追加到Excel文件末尾。
-
文件完整性:这些额外输出会破坏Excel文件的二进制结构,导致Office Excel(对文件格式要求更严格)无法正常打开,但WPS可能有更好的容错机制。
-
立即终止脚本:exit;语句确保文件内容输出完成后立即终止脚本执行,保证下载的Excel文件格式完整无损。
-
您的解决方案简单高效,这是处理PHP文件下载时的一个常见最佳实践。现在代码应该可以在两种办公软件中都正常工作了。