【PHP】利用 xlswriter 扩展导出的Excel文件报错问题

一、问题描述

导出的文件在wps中打开没问题,在office excel中打开会报错如下:

发现"xxx.xlsx"中的部分内容有问题。是否让我们尽量尝试恢复?如果您信任此工作薄的源,请单击"是"。

二、解决方案

在导出程序末尾加上 exit;

三、代码过程

导出使用的是php的扩展包xlswriter

3.1 xlswriter_helper.php

php 复制代码
<?php

namespace 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

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);

        // header
        array_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

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文件下载时的一个常见最佳实践。现在代码应该可以在两种办公软件中都正常工作了。

相关推荐
BingoGo4 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack4 小时前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack1 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
JaguarJack2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo2 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack3 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
QQ5110082854 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
WeiXin_DZbishe4 天前
基于django在线音乐数据采集的设计与实现-计算机毕设 附源码 22647
javascript·spring boot·mysql·django·node.js·php·html5