8

I have a script that generates a little xls table (~25x15). It contains percentages and strings and i have an if operator that sets the current cell as percentage type with this code:

$this->objPHPExcel->getActiveSheet()->getStyle($coords)->getNumberFormat()->setFormatCode('0.00%');

But when i export and look at the file I see it only managed to set type and style about 20 cells. And all the rest are with default settings. I debugged it and realized the problem isn't in my logic. I read about increasing php cache memory - tried it but it didn't work. Please help because i need to export at least 15 times larger table. Thanks in advance!

Martin
  • 1,193
  • 3
  • 12
  • 24
  • 1
    As PHPExcel doesn't impose any limit on the number of styles (though Excel itself does, it's well above 20), and a number of our demo scripts in the /Examples folder use more than 20 different styles, can you please provide a working example of code that demonstrates this problem. It may be that the problem is in a particular style that you are setting rather than after a number of styles. – Mark Baker Aug 05 '13 at 08:39
  • What is `$this` in your question and what is `$coords` in your question and where is the rest of the bare minimum example to reproduce your issue? http://meta.stackexchange.com/questions/22754/sscce-how-to-provide-examples-for-programming-questions – hakre Aug 13 '13 at 11:11
  • @Martin Please accept an answer. Maybe mine ;-) – SteAp May 01 '22 at 21:54

3 Answers3

3

PHPExcel allocates quite some memory

While PHPExcel is a beautiful library, using it may require huge amounts of memory allocated to PHP.

According to this thread, just 5 cells may render 6 MByte of memory usage:

<?php
require_once 'php/PHPExcelSVN/PHPExcel/IOFactory.php';
$objPHPExcel = PHPExcel_IOFactory::load("php/tinytest.xlsx");
$objPHPExcel->setActiveSheetIndex(0);
$objPHPExcel->getActiveSheet()->setCellValue('D2', 50);
echo $objPHPExcel->getActiveSheet()->getCell('D8')->getCalculatedValue() . "
";
echo date('H:i:s') . " Peak memory usage: " . (memory_get_peak_usage(true) / 1024 / 1024) . " MB\r\n";
?>

I get 6MB of memory usage.

Another user even failed with a 256MByte memory setting.

While PHPExcel provides ways to reduce its memory footprint, all reductions turned out to be too small in my case. This page on github provides details of PHPExcel's cache management options. For example, this setting serializes and the GZIPs the cell-structure of a worksheet:

$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_in_memory_gzip;

PHPExcel_Settings::setCacheStorageMethod($cacheMethod);

PHPExcel's FAQ explains this:

Fatal error: Allowed memory size of xxx bytes exhausted (tried to allocate yyy bytes) in zzz on line aaa

PHPExcel holds an "in memory" representation of a spreadsheet, so it is susceptible to PHP's memory limitations. The memory made available to PHP can be increased by editing the value of the memorylimit directive in your php.ini file, or by using iniset('memory_limit', '128M') within your code (ISP permitting);

Some Readers and Writers are faster than others, and they also use differing amounts of memory. You can find some indication of the relative performance and memory usage for the different Readers and Writers, over the different versions of PHPExcel, here http://phpexcel.codeplex.com/Thread/View.aspx?ThreadId=234150

If you've already increased memory to a maximum, or can't change your memory limit, then this discussion on the board describes some of the methods that can be applied to reduce the memory usage of your scripts using PHPExcel http://phpexcel.codeplex.com/Thread/View.aspx?ThreadId=242712

Measurement results for PHP Excel

I instrumented the PHPExcel example file [01simple.php][5] and did some quick testing.

Consume 92 KByte:

for( $n=0; $n<200; $n++ ) {
    $objPHPExcel->setActiveSheetIndex(0) ->setCellValue('A' . $n, 'Miscellaneous glyphs');
}

Consumes 4164 KBytes:

for( $n=0; $n<200; $n++ ) {
    $objPHPExcel->setActiveSheetIndex(0) ->setCellValue('A' . $n, 'Miscellaneous glyphs');
    $objPHPExcel->getActiveSheet()->getStyle('A' . $n)->getAlignment()->setWrapText(true);
}

If one executes this fragment several times unchanged, each fragment consumes around 4 MBytes.

Checking your app is logically correct

To ensure, that your app is logically correct, I'd propose to increase PHP memory first:

ini_set('memory_limit', '32M');

In my case, I have to export to export result data of an online assessment application. While there are less than 100 cells horizontally, I need to export up to several 10.000 rows. While the amount of cells was big, each of my cells holds a number or a string of 3 characters - no formulas, no styles.

In case of strong memory restrictions or large spreadsheets

In my case, none of the cache options reduced the amount as much as required. Plus, the runtime of the application grew enormously.

Finally I had to switch over to old fashioned CSV-data file exports.

SteAp
  • 11,853
  • 10
  • 53
  • 88
  • 1
    Please cite your reference for `Each cell of a PHPExcel spreadsheet amounts to around 20 KBytes of memory.`... my rule of thumb has always been 1k/cell on 32-bit PHP and 1.6k/cell if you're using 64-bit PHP – Mark Baker Aug 11 '13 at 19:29
  • This appears to be little more than a rant against PHPExcel memory management, and doesn't seem to answer the OP's question about styles in any way. OP doesn't mention memory at all. And it barely mentions any of the techniques for reducing memory usage in PHPExcel – Mark Baker Aug 11 '13 at 19:30
  • The problem with COM, and the reason why MS don't recommend it, is that it causes problems when you're trying to work with more than one COM object (or more than one Excel file) at a time.... but it is also limited to Windows servers – Mark Baker Aug 11 '13 at 22:50
  • There are real benefits to COM if you have that option though: full support for all MS Excel features; works outside the PHP memory limitations; faster (native code) - PHPExcel is targeted at people who don't have that access, or can't figure out the complexities of the COM object model – Mark Baker Aug 11 '13 at 23:20
  • Styles can't be cached in the same way as cells, because they're a complex collection of nested objects; and we always recommend setting styles by range rather than individual cell because that creates a single style record for the entire range of cells rather than an individual style record for every cell – Mark Baker Aug 11 '13 at 23:31
  • It's something I'm looking to change for version 2, testing every style setting, and only creating a new style if there's no existing match (though that will create its own performance overhead); and only setting relevant style component objects, rather than creating a full tree of default objects, if style elements are undefined – Mark Baker Aug 11 '13 at 23:32
  • Matching the style that you want against the existing or predefined styles, and setting the cell's xfindex to that style eliminates a lot of the style overhead; but it's a complicated task for a user, otherwise I'd recommend that as a more memory efficient way of working - that's basically what my current v2 code does behind the scenes, discarding the duplicates from memory; but the matching is slow and it has the drawback that any change to an existing style affects all cells that use it – Mark Baker Aug 11 '13 at 23:36
  • On my machine, running the poster's code takes up a maximum "Peak memory usage: 5.5 MB". His own code shows this result. ini_set('memory_limit', '32M'); is therefore completely superfluous, although interesting on bigger spreadsheets in PHPExcel, it's irrelevant here. – Spork Aug 13 '13 at 11:57
2

I ran your code locally and found that all the 26 cells you set to this percentage had the right format and a % sign. I had to uncomment lines 136-137 first, of course.

This must be related to your setup. I cannot imagine you'd have too little memory for a spreadsheet of this size.

For your information, I confirmed it worked on PHP Version 5.4.16 with php excel version version 1.7.6, 2011-02-27. I opened the spreadsheet with MS Excel 2007.

Spork
  • 1,631
  • 1
  • 21
  • 37
  • Also with the latest version, 1.7.9. 17:01:54 Current memory usage: 5.5 MB 17:01:54 Peak memory usage: 5.5 MB – Spork Aug 12 '13 at 16:02
  • It could only be machine dependent if it were memory, but I don't have a particularly impressive machine. I would lean toward a difference in PHP versions or PHPExcel versions. What are yours? – Spork Aug 13 '13 at 11:55
  • Oh, and also which spreadsheet editor you open it with! I've had little bugs when my formats weren't completely correct that were handled widely differently in different spreadsheet editors. – Spork Aug 13 '13 at 11:58
1
<?php
$file = 'output_log.txt';

function get_owner($file)
{
    $stat = stat($file);
    $user = posix_getpwuid($stat['uid']);
    return $user['name'];
}

$format = "UID @ %s: %s\n";

printf($format, date('r'), get_owner($file));

chown($file, 'ross');
printf($format, date('r'), get_owner($file));

clearstatcache();
printf($format, date('r'), get_owner($file));
?>

clearstatcache(); can be useful. Load this function at the start of the php page.

Burhan
  • 263
  • 4
  • 9
  • I tried it but it didn't work. Here is the code that I'm using http://pastebin.com/wjWuX8J0 . I'll be greatly appreciated if u manage to give any other advice. – Martin Aug 06 '13 at 12:20