在PhpSpreadsheet中读取Xlsx文件

12

我想读取一个在Microsoft Excel中创建的xlsx文件,但是当我运行以下代码时...

$Source_File = "test.xlsx";
$Spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($Source_File);

我收到以下错误信息:

Fatal error: Uncaught PhpOffice\PhpSpreadsheet\Reader\Exception: Unable to identify a reader for this file in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/IOFactory.php:163
Stack trace:
  #0 /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/IOFactory.php(93): PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile('file:///home/ar...')
  #1 /var/www/html/Function_Spreadsheet.php(480): PhpOffice\PhpSpreadsheet\IOFactory::load('file:///home/ar...')
  #2 /var/www/html/Function_Home.php(3747): Spreadsheet_Reader_1('/var/www/html/F...', 3745, Array, Array)
  #3 {main} thrown in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/IOFactory.php on line 163

如果我使用$Spreadsheet = IOFactory::load($Source_File);代替,我将会得到相同的错误。

如果我使用$Spreadsheet = $reader->load($Source_File);代替,我将会得到以下错误。

Warning: ZipArchive::getFromName(): Invalid or uninitialized Zip object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 311

Warning: ZipArchive::getFromName(): Invalid or uninitialized Zip object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 313

Notice: Trying to get property 'Relationship' of non-object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 350

Warning: Invalid argument supplied for foreach() in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 350

Warning: ZipArchive::getFromName(): Invalid or uninitialized Zip object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 311

Warning: ZipArchive::getFromName(): Invalid or uninitialized Zip object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 313

Notice: Trying to get property 'Relationship' of non-object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 397

Warning: Invalid argument supplied for foreach() in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 397

Warning: ZipArchive::getFromName(): Invalid or uninitialized Zip object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 311

Warning: ZipArchive::getFromName(): Invalid or uninitialized Zip object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 313

Notice: Trying to get property 'Override' of non-object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 1855

Warning: Invalid argument supplied for foreach() in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 1855

Warning: ZipArchive::close(): Invalid or uninitialized Zip object in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx.php on line 1883

我使用在Ubuntu 18.04上的Apache中的PHP v7.2脚本可以读取和打开文件。我阅读了几篇论坛帖子,建议如下操作:

我尝试在LibreOffice中打开该文件,并将其另存为xlsx格式,但仍然出现相同错误(如果保存为xls则不会有错误)。

我可以创建一个读取器$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();,但当我运行$Spreadsheet = $reader->load($Source_File);$Spreadsheet = IOFactory::load($Source_File);时,我得到相同的错误。

此外,我可以创建一个可以读取xls文件的xls读取器。我还可以创建一个xlsx读取器,但它无法读取xlsx文件,尝试读取xlsx文件时会出现同样的错误。那么,为什么对于xlsx文件会出现错误?

我还阅读了错误消息所指向的源代码(IOFactory.php),并找到了错误发生的位置(大约在第139行附近)...

//Let's see if we are lucky
if (isset($reader) && $reader->canRead($filename))
{
    return $reader;
}

......而我搜索了/vendor/phpoffice/phpspreadsheet/中的所有内容,却找不到canRead的定义。 canRead的定义在哪里呢?我认为如果我能阅读canRead的定义,那么或许我就能理解问题的根本原因。

更新:

我从评论和讨论中了解到,canRead()\PhpSpreadsheet\Reader\Xlsx.php中定义,大约从第65行开始。 在canRead()中,$zip->open($pFilename)返回一个错误代码ZipArchive::ER_NOENT,这意味着"没有这个文件"。然而,文件是存在的。 那么,为什么会发生这种错误?

更新-2018-12-18

这个网页表明有多种类型的xlsx文件。因此,我运行file test.xlsx,显示Microsoft Excel 2007+。然后我在LibreOffice Calc中打开电子表格,并将其保存为OOXML类型的xlsx文件,然后重新运行file test.xlsx,显示Microsoft OOXML。然后我重新运行PHP脚本,但是仍然得到相同的错误。因此,似乎我的xlsx文件类型不是问题所在。

因此,我决定使用PHPExcel(尽管它已被弃用)完成一些必要的工作。当我使用PHPExcel运行脚本时,我收到了一个关于canRead()无法检测到xlsx文件的类似错误。

所以,我继续阅读这个网页并遵循wesood的最后建议,该建议来自这个网页中接受的答案。这个解决方案对我有用:在文件/PHPExcel/IOFactory.php中,我在if (isset($reader) && $reader->canRead($filename))之前立即添加了PHPExcel_Settings::setZipClass(\PHPExcel_Settings::PCLZIP);

然而,我仍然想知道如何在PhpSpreadsheet中解决这个问题。看来我需要了解更多关于pclzip的工作原理,以及是否需要对PhpSpreadsheet执行类似的操作。

更新2019年2月10日:

今天我尝试运行脚本,似乎添加PHPExcel_Settings::setZipClass(\PHPExcel_Settings::PCLZIP);不再起作用了。所以,我又卡住了......

我做错了什么? 欢迎任何帮助!

更新2019-02-18:

根据评论中的建议,我使用在谷歌搜索结果中找到的随机XLSX文件(例如这个文件),它们要么是Excel 2007+类型,要么是Microsoft OOXML 类型,但是PhpSpreadsheet仍然显示相同的错误:

致命错误:未捕获的PhpOffice\PhpSpreadsheet\Reader\Exception: 无法识别该文件的读取程序, 位于/var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/IOFactory.php:176 堆栈跟踪:#0 /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/IOFactory.php(113): PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile('file:///var/www...') #1 /var/www/html/Function_Spreadsheet.php(798): PhpOffice\PhpSpreadsheet\IOFactory::identify('file:///var/www...') #2 /var/www/html/Function_Home.php(3748): Spreadsheet_Reader_1('/var/www/html/F...', 3746, Array, Array) #3 {main} thrown in /var/www/html/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/IOFactory.php on line 176


1
你要找的代码是:https://github.com/PHPOffice/PhpSpreadsheet/blob/develop/src/PhpSpreadsheet/Reader/Xlsx.php#L69 - Martin
根据你所说的和查看GitHub代码,我只能推测你正在尝试加载的文件不是phpspreadsheet认为应该是xlsx格式的。 - Martin
你能用7-zip打开你的测试文件Test.xlsx来验证它是否是一个ZIP压缩文件吗?你要在压缩文件中寻找一个名为workbook.xml的文件。 - Martin
1
它不可能给出相同的错误 - 它没有使用相同的代码。load函数在我之前提到的同一文件的第389行。你能再次检查一下load函数会给出什么错误吗? - Martin
1
请在提问时添加主标签。人们通常会关注主标签。我已经添加了php标签。如果您早些时候添加了它,我就能更早地看到它了。您的问题没有得到足够的关注是因为缺少php标签。 - Shahbaz A.
显示剩余10条评论
5个回答

25

根据我的理解,您缺少一部分内容。为什么不先创建一个读取器,然后再加载文件。

尝试下面的代码。它可以识别扩展名并相应地创建该类型的阅读器。

$inputFileName = "Text.xlsx";

/**  Identify the type of $inputFileName  **/
$inputFileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($inputFileName);

/**  Create a new Reader of the type that has been identified  **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);

/**  Load $inputFileName to a Spreadsheet Object  **/
$spreadsheet = $reader->load($inputFileName);

/**  Convert Spreadsheet Object to an Array for ease of use  **/
$schdeules = $spreadsheet->getActiveSheet()->toArray();

现在您可以简单地在结果数组上运行 foreach 循环。

foreach( $schdeules as $single_schedule )
{               
    echo '<div class="row">';
    foreach( $single_schedule as $single_item )
    {
        echo '<p class="item">' . $single_item . '</p>';
    }
    echo '</div>';
}

这是已经测试过且可用的代码。


1
我使用$inputFileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($inputFileName);时出现以下错误:Fatal error: Uncaught PhpOffice\PhpSpreadsheet\Reader\Exception: Unable to identify a reader for this file。您对此错误的原因有何想法?我正在使用的XLSX输入文件是Microsoft Excel 2007+文件类型。 - Arya
那么你的文件可能存在一些错误。为什么不试试样例文件呢?这里是标准样例的 Github 链接:https://github.com/PHPOffice/PhpSpreadsheet/tree/master/samples/Reader/sampleData - Shahbaz A.
如果示例可以正常工作,那么您可以检查您的文件存在什么问题以及您的文件与正常工作的文件之间的区别。 - Shahbaz A.
您提供的 Github 链接中没有 XLSX 文件样本,我只看到了 CSV、TSV 和 XLS 文件。是否有我没有注意到的 XLSX 文件? - Arya
我下载了另外几个XLSX文件[http://file-examples.com/wp-content/uploads/2017/02/file_example_XLSX_10.xlsx],它们都是“Excel 2007+”或“Microsoft OOXML”格式,但所有这些文件都显示相同的错误。因此,看来问题不在于XLSX文件本身。也许是我的系统配置有问题,但具体是什么呢? - Arya
我无法读取Excel文件。 (https://stackoverflow.com/q/64906846/6854117) - Moeez

3

我遇到了相同的问题,是在我的Mac上将.xlsx文件添加到git仓库后出现的。
问题在于git自动转换了行尾符。

解决方案是将以下内容添加到.gitattributes文件中:

*.xls   binary
*.xlsx  binary

2
我在尝试加载XLSX文件时遇到了完全相同的错误。对我个人而言,我发现了一个非常简单的解决方法来解决我的问题。我手动从文件名中获取扩展名为xlsx。我注意到我写的一些旧PHP Spreadsheet库代码使用的扩展名为Xls。所以我尝试加载Xlsx并且它完美地工作了。
这是我用来正确加载扩展名的代码。它只是获取最后一个句点后面的所有字符,然后将该子字符串的第一个字符大写。ucfirst仅将传递给它的字符串的第一个字母大写。 substr返回子字符串,其中第一个参数是要从中抓取的字符串,第二个参数是在给定字符串中开始子字符串的索引。最后,strrpos找到给定字符串中子字符串的最后一个出现。 https://www.php.net/manual/en/function.ucfirst.php https://www.php.net/manual/en/function.strrpos https://www.php.net/manual/en/function.substr.php
$inputFileType = ucfirst(substr($cccFile, strrpos($cccFile, '.') + 1));

/**  Create a new Reader of the type defined in $inputFileType  **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);

我曾经遇到过类似的问题,后来我使用了 ucfirst 命令解决了它。

“ucfirst”命令是一个IT技术中常用的字符串函数,它可以将字符串的第一个字符变为大写字母。


请解释第一行的作用。 - Jimmy Adaro
我在第二段解释得非常清楚。 - dmikester1
我理解这段代码,但是对于不懂得strrpos,substr + 1和/或者 ucfirst的人来说,可能会感到困惑。 - Jimmy Adaro
1
好的,我会尝试添加一些澄清的文本。 - dmikester1

0
我在Drupal页面中使用"private://..."作为文件路径时遇到了类似的问题。在PHPExcel中使用getFromZipArchive(在PhpSpreadsheet中应该类似)不能读取"private://..."这样的文件路径方案。将其转换为本地路径后,它可以正常工作。
在您的情况下,您有像"file:///home/ar..."这样的路径方案。所以使用"/home/ar..."代替即可。

0
使用这个。它会显示.xlsx文件。
   $inputFileName = public_path('asset/docs/Filename.xlsx');
    
   /** Load $inputFileName to a Spreadsheet Object  **/
   $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($inputFileName);
   $writer = IOFactory::createWriter($spreadsheet, 'Html');
   $message = $writer->save('php://output');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接