diff --git a/ChangeLog b/ChangeLog index a757acbcd..7e8165da9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -145,6 +145,7 @@ - rfe #1640812 [auth] Add example for OpenID authentication using signon method. - rfe #1312657 [dbi] Default to mysqli extension. - rfe #1168350 [interface] Add clear button to SQL edit box. +- [core] Update library PHPExcel to version 1.7.6 3.3.10.0 (not yet released) - patch #3147400 [structure] Aria table size printed as unknown, diff --git a/js/functions.js b/js/functions.js index b86ffe330..8abdc5113 100644 --- a/js/functions.js +++ b/js/functions.js @@ -380,328 +380,6 @@ function checkSqlQuery(theForm) return true; } // end of the 'checkSqlQuery()' function -// Global variable row_class is set to even -var row_class = 'even'; - -/** -* Generates a row dynamically in the differences table displaying -* the complete statistics of difference in table like number of -* rows to be updated, number of rows to be inserted, number of -* columns to be added, number of columns to be removed, etc. -* -* @param index index of matching table -* @param update_size number of rows/column to be updated -* @param insert_size number of rows/coulmns to be inserted -* @param remove_size number of columns to be removed -* @param insert_index number of indexes to be inserted -* @param remove_index number of indexes to be removed -* @param img_obj image object -* @param table_name name of the table -*/ - -function showDetails(i, update_size, insert_size, remove_size, insert_index, remove_index, img_obj, table_name) -{ - // The path of the image is split to facilitate comparison - var relative_path = (img_obj.src).split("themes/"); - - // The image source is changed when the showDetails function is called. - if (relative_path[1] == 'original/img/new_data_hovered.jpg') { - img_obj.src = "./themes/original/img/new_data_selected_hovered.jpg"; - img_obj.alt = PMA_messages['strClickToUnselect']; //only for IE browser - } else if (relative_path[1] == 'original/img/new_struct_hovered.jpg') { - img_obj.src = "./themes/original/img/new_struct_selected_hovered.jpg"; - img_obj.alt = PMA_messages['strClickToUnselect']; - } else if (relative_path[1] == 'original/img/new_struct_selected_hovered.jpg') { - img_obj.src = "./themes/original/img/new_struct_hovered.jpg"; - img_obj.alt = PMA_messages['strClickToSelect']; - } else if (relative_path[1] == 'original/img/new_data_selected_hovered.jpg') { - img_obj.src = "./themes/original/img/new_data_hovered.jpg"; - img_obj.alt = PMA_messages['strClickToSelect']; - } - - var div = document.getElementById("list"); - var table = div.getElementsByTagName("table")[0]; - var table_body = table.getElementsByTagName("tbody")[0]; - - //Global variable row_class is being used - if (row_class == 'even') { - row_class = 'odd'; - } else { - row_class = 'even'; - } - // If the red or green button against a table name is pressed then append a new row to show the details of differences of this table. - if ((relative_path[1] != 'original/img/new_struct_selected_hovered.jpg') && (relative_path[1] != 'original/img/new_data_selected_hovered.jpg')) { - - var newRow = document.createElement("tr"); - newRow.setAttribute("class", row_class); - newRow.className = row_class; - // Id assigned to this row element is same as the index of this table name in the matching_tables/source_tables_uncommon array - newRow.setAttribute("id" , i); - - var table_name_cell = document.createElement("td"); - table_name_cell.align = "center"; - table_name_cell.innerHTML = table_name ; - - newRow.appendChild(table_name_cell); - - var create_table = document.createElement("td"); - create_table.align = "center"; - - var add_cols = document.createElement("td"); - add_cols.align = "center"; - - var remove_cols = document.createElement("td"); - remove_cols.align = "center"; - - var alter_cols = document.createElement("td"); - alter_cols.align = "center"; - - var add_index = document.createElement("td"); - add_index.align = "center"; - - var delete_index = document.createElement("td"); - delete_index.align = "center"; - - var update_rows = document.createElement("td"); - update_rows.align = "center"; - - var insert_rows = document.createElement("td"); - insert_rows.align = "center"; - - var tick_image = document.createElement("img"); - tick_image.src = "./themes/original/img/s_success.png"; - - if (update_size == '' && insert_size == '' && remove_size == '') { - /** - This is the case when the table needs to be created in target database. - */ - create_table.appendChild(tick_image); - add_cols.innerHTML = "--"; - remove_cols.innerHTML = "--"; - alter_cols.innerHTML = "--"; - delete_index.innerHTML = "--"; - add_index.innerHTML = "--"; - update_rows.innerHTML = "--"; - insert_rows.innerHTML = "--"; - - newRow.appendChild(create_table); - newRow.appendChild(add_cols); - newRow.appendChild(remove_cols); - newRow.appendChild(alter_cols); - newRow.appendChild(delete_index); - newRow.appendChild(add_index); - newRow.appendChild(update_rows); - newRow.appendChild(insert_rows); - - } else if (update_size == '' && remove_size == '') { - /** - This is the case when data difference is displayed in the - table which is present in source but absent from target database - */ - create_table.innerHTML = "--"; - add_cols.innerHTML = "--"; - remove_cols.innerHTML = "--"; - alter_cols.innerHTML = "--"; - add_index.innerHTML = "--"; - delete_index.innerHTML = "--"; - update_rows.innerHTML = "--"; - insert_rows.innerHTML = insert_size; - - newRow.appendChild(create_table); - newRow.appendChild(add_cols); - newRow.appendChild(remove_cols); - newRow.appendChild(alter_cols); - newRow.appendChild(delete_index); - newRow.appendChild(add_index); - newRow.appendChild(update_rows); - newRow.appendChild(insert_rows); - - } else if (remove_size == '') { - /** - This is the case when data difference between matching_tables is displayed. - */ - create_table.innerHTML = "--"; - add_cols.innerHTML = "--"; - remove_cols.innerHTML = "--"; - alter_cols.innerHTML = "--"; - add_index.innerHTML = "--"; - delete_index.innerHTML = "--"; - update_rows.innerHTML = update_size; - insert_rows.innerHTML = insert_size; - - newRow.appendChild(create_table); - newRow.appendChild(add_cols); - newRow.appendChild(remove_cols); - newRow.appendChild(alter_cols); - newRow.appendChild(delete_index); - newRow.appendChild(add_index); - newRow.appendChild(update_rows); - newRow.appendChild(insert_rows); - - } else { - /** - This is the case when structure difference between matching_tables id displayed - */ - create_table.innerHTML = "--"; - add_cols.innerHTML = insert_size; - remove_cols.innerHTML = remove_size; - alter_cols.innerHTML = update_size; - delete_index.innerHTML = remove_index; - add_index.innerHTML = insert_index; - update_rows.innerHTML = "--"; - insert_rows.innerHTML = "--"; - - newRow.appendChild(create_table); - newRow.appendChild(add_cols); - newRow.appendChild(remove_cols); - newRow.appendChild(alter_cols); - newRow.appendChild(delete_index); - newRow.appendChild(add_index); - newRow.appendChild(update_rows); - newRow.appendChild(insert_rows); - } - table_body.appendChild(newRow); - - } else if ((relative_path[1] != 'original/img/new_struct_hovered.jpg') && (relative_path[1] != 'original/img/new_data_hovered.jpg')) { - //The case when the row showing the details need to be removed from the table i.e. the difference button is deselected now. - var table_rows = table_body.getElementsByTagName("tr"); - var j; - var index = 0; - for (j=0; j < table_rows.length; j++) - { - if (table_rows[j].id == i) { - index = j; - table_rows[j].parentNode.removeChild(table_rows[j]); - } - } - //The table row css is being adjusted. Class "odd" for odd rows and "even" for even rows should be maintained. - for(index = 0; index < table_rows.length; index++) - { - row_class_element = table_rows[index].getAttribute('class'); - if (row_class_element == "even") { - table_rows[index].setAttribute("class","odd"); // for Mozilla firefox - table_rows[index].className = "odd"; // for IE browser - } else { - table_rows[index].setAttribute("class","even"); // for Mozilla firefox - table_rows[index].className = "even"; // for IE browser - } - } - } -} - -/** - * Changes the image on hover effects - * - * @param img_obj the image object whose source needs to be changed - * - */ -function change_Image(img_obj) -{ - var relative_path = (img_obj.src).split("themes/"); - - if (relative_path[1] == 'original/img/new_data.jpg') { - img_obj.src = "./themes/original/img/new_data_hovered.jpg"; - } else if (relative_path[1] == 'original/img/new_struct.jpg') { - img_obj.src = "./themes/original/img/new_struct_hovered.jpg"; - } else if (relative_path[1] == 'original/img/new_struct_hovered.jpg') { - img_obj.src = "./themes/original/img/new_struct.jpg"; - } else if (relative_path[1] == 'original/img/new_data_hovered.jpg') { - img_obj.src = "./themes/original/img/new_data.jpg"; - } else if (relative_path[1] == 'original/img/new_data_selected.jpg') { - img_obj.src = "./themes/original/img/new_data_selected_hovered.jpg"; - } else if(relative_path[1] == 'original/img/new_struct_selected.jpg') { - img_obj.src = "./themes/original/img/new_struct_selected_hovered.jpg"; - } else if (relative_path[1] == 'original/img/new_struct_selected_hovered.jpg') { - img_obj.src = "./themes/original/img/new_struct_selected.jpg"; - } else if (relative_path[1] == 'original/img/new_data_selected_hovered.jpg') { - img_obj.src = "./themes/original/img/new_data_selected.jpg"; - } -} - -/** - * Generates the URL containing the list of selected table ids for synchronization and - * a variable checked for confirmation of deleting previous rows from target tables - * - * @param token the token generated for each PMA form - * - */ -function ApplySelectedChanges(token) -{ - var div = document.getElementById("list"); - var table = div.getElementsByTagName('table')[0]; - var table_body = table.getElementsByTagName('tbody')[0]; - // Get all the rows from the details table - var table_rows = table_body.getElementsByTagName('tr'); - var x = table_rows.length; - var i; - /** - Append the token at the beginning of the query string followed by - Table_ids that shows that "Apply Selected Changes" button is pressed - */ - var append_string = "?token="+token+"&Table_ids="+1; - for(i=0; i') + $('') .insertBefore(e); PMA_set_status_label(e.id); $('' + e.title + '') .insertBefore(e) .click(function() { - $('#' + e.id).toggle('clip'); - PMA_set_status_label(e.id); + $('#' + e.id).toggle('clip', function() { + PMA_set_status_label(e.id); + }); return false; }); }); diff --git a/js/messages.php b/js/messages.php index 9da01ca05..0f7c8c7c6 100644 --- a/js/messages.php +++ b/js/messages.php @@ -126,6 +126,9 @@ foreach ($js_messages as $name => $js_message) { /* Calendar */ echo "var themeCalendarImage = '" . $GLOBALS['pmaThemeImage'] . 'b_calendar.png' . "';\n"; +/* Image path */ +echo "var pmaThemeImage = '" . $GLOBALS['pmaThemeImage'] . "';\n"; + /* Version */ echo "var pmaversion = '" . PMA_VERSION . "';\n"; diff --git a/js/server_synchronize.js b/js/server_synchronize.js index b360d1564..e327a7b40 100644 --- a/js/server_synchronize.js +++ b/js/server_synchronize.js @@ -3,6 +3,303 @@ * for server_synchronize.php * */ + +// Global variable row_class is set to even +var row_class = 'even'; + +/** +* Generates a row dynamically in the differences table displaying +* the complete statistics of difference in table like number of +* rows to be updated, number of rows to be inserted, number of +* columns to be added, number of columns to be removed, etc. +* +* @param index index of matching table +* @param update_size number of rows/column to be updated +* @param insert_size number of rows/coulmns to be inserted +* @param remove_size number of columns to be removed +* @param insert_index number of indexes to be inserted +* @param remove_index number of indexes to be removed +* @param img_obj image object +* @param table_name name of the table +*/ + +function showDetails(i, update_size, insert_size, remove_size, insert_index, remove_index, img_obj, table_name) +{ + // a jQuery object + var $img = $(img_obj); + + $img.toggleClass('selected'); + + // The image source is changed when the showDetails function is called. + if ($img.hasClass('selected')) { + if ($img.hasClass('struct_img')) { + $img.attr('src', pmaThemeImage + 'new_struct_selected.jpg'); + } + if ($img.hasClass('data_img')) { + $img.attr('src', pmaThemeImage + 'new_data_selected.jpg'); + } + } else { + if ($img.hasClass('struct_img')) { + $img.attr('src', pmaThemeImage + 'new_struct.jpg'); + } + if ($img.hasClass('data_img')) { + $img.attr('src', pmaThemeImage + 'new_data.jpg'); + } + } + + var div = document.getElementById("list"); + var table = div.getElementsByTagName("table")[0]; + var table_body = table.getElementsByTagName("tbody")[0]; + + //Global variable row_class is being used + if (row_class == 'even') { + row_class = 'odd'; + } else { + row_class = 'even'; + } + // If the red or green button against a table name is pressed then append a new row to show the details of differences of this table. + if ($img.hasClass('selected')) { + var newRow = document.createElement("tr"); + newRow.setAttribute("class", row_class); + newRow.className = row_class; + // Id assigned to this row element is same as the index of this table name in the matching_tables/source_tables_uncommon array + newRow.setAttribute("id" , i); + + var table_name_cell = document.createElement("td"); + table_name_cell.align = "center"; + table_name_cell.innerHTML = table_name ; + + newRow.appendChild(table_name_cell); + + var create_table = document.createElement("td"); + create_table.align = "center"; + + var add_cols = document.createElement("td"); + add_cols.align = "center"; + + var remove_cols = document.createElement("td"); + remove_cols.align = "center"; + + var alter_cols = document.createElement("td"); + alter_cols.align = "center"; + + var add_index = document.createElement("td"); + add_index.align = "center"; + + var delete_index = document.createElement("td"); + delete_index.align = "center"; + + var update_rows = document.createElement("td"); + update_rows.align = "center"; + + var insert_rows = document.createElement("td"); + insert_rows.align = "center"; + + var tick_image = document.createElement("img"); + tick_image.src = pmaThemeImage + "s_success.png"; + + if (update_size == '' && insert_size == '' && remove_size == '') { + /** + This is the case when the table needs to be created in target database. + */ + create_table.appendChild(tick_image); + add_cols.innerHTML = "--"; + remove_cols.innerHTML = "--"; + alter_cols.innerHTML = "--"; + delete_index.innerHTML = "--"; + add_index.innerHTML = "--"; + update_rows.innerHTML = "--"; + insert_rows.innerHTML = "--"; + + newRow.appendChild(create_table); + newRow.appendChild(add_cols); + newRow.appendChild(remove_cols); + newRow.appendChild(alter_cols); + newRow.appendChild(delete_index); + newRow.appendChild(add_index); + newRow.appendChild(update_rows); + newRow.appendChild(insert_rows); + + } else if (update_size == '' && remove_size == '') { + /** + This is the case when data difference is displayed in the + table which is present in source but absent from target database + */ + create_table.innerHTML = "--"; + add_cols.innerHTML = "--"; + remove_cols.innerHTML = "--"; + alter_cols.innerHTML = "--"; + add_index.innerHTML = "--"; + delete_index.innerHTML = "--"; + update_rows.innerHTML = "--"; + insert_rows.innerHTML = insert_size; + + newRow.appendChild(create_table); + newRow.appendChild(add_cols); + newRow.appendChild(remove_cols); + newRow.appendChild(alter_cols); + newRow.appendChild(delete_index); + newRow.appendChild(add_index); + newRow.appendChild(update_rows); + newRow.appendChild(insert_rows); + + } else if (remove_size == '') { + /** + This is the case when data difference between matching_tables is displayed. + */ + create_table.innerHTML = "--"; + add_cols.innerHTML = "--"; + remove_cols.innerHTML = "--"; + alter_cols.innerHTML = "--"; + add_index.innerHTML = "--"; + delete_index.innerHTML = "--"; + update_rows.innerHTML = update_size; + insert_rows.innerHTML = insert_size; + + newRow.appendChild(create_table); + newRow.appendChild(add_cols); + newRow.appendChild(remove_cols); + newRow.appendChild(alter_cols); + newRow.appendChild(delete_index); + newRow.appendChild(add_index); + newRow.appendChild(update_rows); + newRow.appendChild(insert_rows); + + } else { + /** + This is the case when structure difference between matching_tables id displayed + */ + create_table.innerHTML = "--"; + add_cols.innerHTML = insert_size; + remove_cols.innerHTML = remove_size; + alter_cols.innerHTML = update_size; + delete_index.innerHTML = remove_index; + add_index.innerHTML = insert_index; + update_rows.innerHTML = "--"; + insert_rows.innerHTML = "--"; + + newRow.appendChild(create_table); + newRow.appendChild(add_cols); + newRow.appendChild(remove_cols); + newRow.appendChild(alter_cols); + newRow.appendChild(delete_index); + newRow.appendChild(add_index); + newRow.appendChild(update_rows); + newRow.appendChild(insert_rows); + } + table_body.appendChild(newRow); + + } else { + //The case when the row showing the details need to be removed from the table i.e. the difference button is deselected now. + var table_rows = table_body.getElementsByTagName("tr"); + var j; + var index = 0; + for (j=0; j < table_rows.length; j++) + { + if (table_rows[j].id == i) { + index = j; + table_rows[j].parentNode.removeChild(table_rows[j]); + } + } + //The table row css is being adjusted. Class "odd" for odd rows and "even" for even rows should be maintained. + for(index = 0; index < table_rows.length; index++) + { + row_class_element = table_rows[index].getAttribute('class'); + if (row_class_element == "even") { + table_rows[index].setAttribute("class","odd"); // for Mozilla firefox + table_rows[index].className = "odd"; // for IE browser + } else { + table_rows[index].setAttribute("class","even"); // for Mozilla firefox + table_rows[index].className = "even"; // for IE browser + } + } + } +} + +/** + * Generates the URL containing the list of selected table ids for synchronization and + * a variable checked for confirmation of deleting previous rows from target tables + * + * @param token the token generated for each PMA form + * + */ +function ApplySelectedChanges(token) +{ + var div = document.getElementById("list"); + var table = div.getElementsByTagName('table')[0]; + var table_body = table.getElementsByTagName('tbody')[0]; + // Get all the rows from the details table + var table_rows = table_body.getElementsByTagName('tr'); + var x = table_rows.length; + var i; + /** + Append the token at the beginning of the query string followed by + Table_ids that shows that "Apply Selected Changes" button is pressed + */ + var append_string = "?token="+token+"&Table_ids="+1; + for(i=0; i 0) { - $("#togglequerybox").trigger('click'); + $received_data = $(data); + $zero_row_results = $received_data.find('textarea[name="sql_query"]'); + // if zero rows are returned from the query execution + if ($zero_row_results.length > 0) { + $('#sqlquery').val($zero_row_results.val()); + } else { + $('#sqlqueryresults').show(); + $("#sqlqueryresults").html(data); + $("#sqlqueryresults").trigger('appendAnchor'); + $('#togglequerybox').show(); + if($("#togglequerybox").siblings(":visible").length > 0) { + $("#togglequerybox").trigger('click'); + } + PMA_init_slider(); } - PMA_init_slider(); } }) // end $.post() }) // end SQL Query submit @@ -998,10 +1005,14 @@ function PMA_changeClassForColumn($this_th, newclass) { var th_index = $this_th.index(); // .eq() is zero-based th_index--; - var $tr_with_data = $this_th.closest('table').find('tbody tr ').has('td.data'); - $tr_with_data.each(function() { - $(this).find('td.data:eq('+th_index+')').toggleClass(newclass); - }); + var $tds = $this_th.closest('table').find('tbody tr').find('td.data:eq('+th_index+')'); + if ($this_th.data('has_class_'+newclass)) { + $tds.removeClass(newclass); + $this_th.data('has_class_'+newclass, false); + } else { + $tds.addClass(newclass); + $this_th.data('has_class_'+newclass, true); + } } $(document).ready(function() { diff --git a/libraries/PHPExcel/PHPExcel.php b/libraries/PHPExcel/PHPExcel.php index c54d421ac..cdb4ab950 100644 --- a/libraries/PHPExcel/PHPExcel.php +++ b/libraries/PHPExcel/PHPExcel.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -30,12 +30,6 @@ if (!defined('PHPEXCEL_ROOT')) { define('PHPEXCEL_ROOT', dirname(__FILE__) . '/'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } @@ -44,7 +38,7 @@ if (!defined('PHPEXCEL_ROOT')) { * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel { @@ -628,7 +622,7 @@ class PHPExcel // then update cellXf indexes for cells foreach ($this->_workSheetCollection as $worksheet) { foreach ($worksheet->getCellCollection(false) as $cellID) { - $cell = $sheet->getCell($cellID); + $cell = $worksheet->getCell($cellID); $xfIndex = $cell->getXfIndex(); if ($xfIndex > $pIndex ) { // decrease xf index by 1 diff --git a/libraries/PHPExcel/PHPExcel/Autoloader.php b/libraries/PHPExcel/PHPExcel/Autoloader.php index e66ce60d2..1164cf1f7 100644 --- a/libraries/PHPExcel/PHPExcel/Autoloader.php +++ b/libraries/PHPExcel/PHPExcel/Autoloader.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,11 +20,20 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ +PHPExcel_Autoloader::Register(); +PHPExcel_Shared_ZipStreamWrapper::register(); +// check mbstring.func_overload +if (ini_get('mbstring.func_overload') & 2) { + throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); +} +PHPExcel_Shared_String::buildCharacterSets(); + + class PHPExcel_Autoloader { public static function Register() { diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/APC.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/APC.php index dae46c23f..2e88d9235 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/APC.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/APC.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_APC extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/CacheBase.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/CacheBase.php index 208ed0243..3e8cd2fc5 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/CacheBase.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/CacheBase.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_CacheBase { @@ -98,9 +98,7 @@ class PHPExcel_CachedObjectStorage_CacheBase { * @throws Exception */ public function updateCacheData(PHPExcel_Cell $cell) { - $pCoord = $cell->getCoordinate(); - - return $this->addCacheData($pCoord,$cell); + return $this->addCacheData($cell->getCoordinate(),$cell); } // function updateCacheData() @@ -140,9 +138,9 @@ class PHPExcel_CachedObjectStorage_CacheBase { */ public function getSortedCellList() { $sortKeys = array(); - foreach ($this->_cellCache as $coord => $value) { - list($colNum,$rowNum) = sscanf($coord,'%[A-Z]%d'); - $sortKeys[sprintf('%09d%3s',$rowNum,$colNum)] = $coord; + foreach (array_keys($this->_cellCache) as $coord) { + list($column,$row) = sscanf($coord,'%[A-Z]%d'); + $sortKeys[sprintf('%09d%3s',$row,$column)] = $coord; } ksort($sortKeys); diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/DiscISAM.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/DiscISAM.php index dff52faae..349be2c65 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/DiscISAM.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/DiscISAM.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { @@ -112,7 +112,7 @@ class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage parent::copyCellCollection($parent); // Get a new id for the new file name $baseUnique = $this->_getUniqueID(); - $newFileName = sys_get_temp_dir().'/PHPExcel.'.$baseUnique.'.cache'; + $newFileName = PHPExcel_Shared_File::sys_get_temp_dir().'/PHPExcel.'.$baseUnique.'.cache'; // Copy the existing cell cache file copy ($this->_fileName,$newFileName); $this->_fileName = $newFileName; @@ -140,7 +140,7 @@ class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage parent::__construct($parent); if (is_null($this->_fileHandle)) { $baseUnique = $this->_getUniqueID(); - $this->_fileName = sys_get_temp_dir().'/PHPExcel.'.$baseUnique.'.cache'; + $this->_fileName = PHPExcel_Shared_File::sys_get_temp_dir().'/PHPExcel.'.$baseUnique.'.cache'; $this->_fileHandle = fopen($this->_fileName,'a+'); } } // function __construct() diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/ICache.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/ICache.php index 4731b8e44..35215a0f6 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/ICache.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/ICache.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ interface PHPExcel_CachedObjectStorage_ICache { diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memcache.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memcache.php index 74df8e852..3e2d30d00 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memcache.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memcache.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { @@ -234,6 +234,3 @@ class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage } // function __destruct() } - - -?> diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memory.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memory.php index 4b59b91f7..1824f72d9 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memory.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Memory.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { @@ -68,6 +68,19 @@ class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_C } // function getCacheData() + public function copyCellCollection(PHPExcel_Worksheet $parent) { + parent::copyCellCollection($parent); + + $newCollection = array(); + foreach($this->_cellCache as $k => &$cell) { + $newCollection[$k] = clone $cell; + $newCollection[$k]->attach($parent); + } + + $this->_cellCache = $newCollection; + } + + public function unsetWorksheetCells() { // Because cells are all stored as intact objects in memory, we need to detach each one from the parent foreach($this->_cellCache as $k => &$cell) { diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemoryGZip.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemoryGZip.php index 394faf275..5bc4b9902 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemoryGZip.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemoryGZip.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemorySerialized.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemorySerialized.php index 0b5b99713..4fa351b90 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemorySerialized.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/MemorySerialized.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/PHPTemp.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/PHPTemp.php index 54810d82d..711d5ebc2 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/PHPTemp.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/PHPTemp.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { diff --git a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Wincache.php b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Wincache.php index aa075beba..844979dbc 100644 --- a/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Wincache.php +++ b/libraries/PHPExcel/PHPExcel/CachedObjectStorage/Wincache.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_CachedObjectStorage - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache { @@ -228,6 +228,3 @@ class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage } // function __destruct() } - - -?> \ No newline at end of file diff --git a/libraries/PHPExcel/PHPExcel/Calculation.php b/libraries/PHPExcel/PHPExcel/Calculation.php index e32891abd..0833129cf 100644 --- a/libraries/PHPExcel/PHPExcel/Calculation.php +++ b/libraries/PHPExcel/PHPExcel/Calculation.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,25 +33,31 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } -/** Matrix */ -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/Matrix.php'; +if (!defined('CALCULATION_REGEXP_CELLREF')) { + // Test for support of \P (multibyte options) in PCRE + if(defined('PREG_BAD_UTF8_ERROR')) { + // Cell reference (cell or range of cells, with or without a sheet reference) + define('CALCULATION_REGEXP_CELLREF','((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d{1,7})'); + // Named Range of cells + define('CALCULATION_REGEXP_NAMEDRANGE','((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?([_A-Z][_A-Z0-9\.]*)'); + } else { + // Cell reference (cell or range of cells, with or without a sheet reference) + define('CALCULATION_REGEXP_CELLREF','(((\w*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d+)'); + // Named Range of cells + define('CALCULATION_REGEXP_NAMEDRANGE','(((\w*)|(\'.*\')|(\".*\"))!)?([_A-Z][_A-Z0-9\.]*)'); + } +} /** * PHPExcel_Calculation (Singleton) * - * @category PHPExcel - * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @category PHPExcel + * @package PHPExcel_Calculation + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Calculation { @@ -63,12 +69,12 @@ class PHPExcel_Calculation { const CALCULATION_REGEXP_STRING = '"(?:[^"]|"")*"'; // Opening bracket const CALCULATION_REGEXP_OPENBRACE = '\('; - // Function + // Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it) const CALCULATION_REGEXP_FUNCTION = '@?([A-Z][A-Z0-9\.]*)[\s]*\('; // Cell reference (cell or range of cells, with or without a sheet reference) - const CALCULATION_REGEXP_CELLREF = '(((\w*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d+)'; + const CALCULATION_REGEXP_CELLREF = CALCULATION_REGEXP_CELLREF; // Named Range of cells - const CALCULATION_REGEXP_NAMEDRANGE = '(((\w*)|(\'.*\')|(\".*\"))!)?([_A-Z][_A-Z0-9]*)'; + const CALCULATION_REGEXP_NAMEDRANGE = CALCULATION_REGEXP_NAMEDRANGE; // Error const CALCULATION_REGEXP_ERROR = '\#[A-Z][A-Z0_\/]*[!\?]?'; @@ -119,11 +125,16 @@ class PHPExcel_Calculation { /** * List of operators that can be used within formulae + * The true/false value indicates whether it is a binary operator or a unary operator * * @access private * @var array */ - private static $_operators = array('+', '-', '*', '/', '^', '&', '%', '~', '>', '<', '=', '>=', '<=', '<>', '|', ':'); + private static $_operators = array('+' => true, '-' => true, '*' => true, '/' => true, + '^' => true, '&' => true, '%' => false, '~' => false, + '>' => true, '<' => true, '=' => true, '>=' => true, + '<=' => true, '<>' => true, '|' => true, ':' => true + ); /** @@ -132,7 +143,11 @@ class PHPExcel_Calculation { * @access private * @var array */ - private static $_binaryOperators = array('+', '-', '*', '/', '^', '&', '>', '<', '=', '>=', '<=', '<>', '|', ':'); + private static $_binaryOperators = array('+' => true, '-' => true, '*' => true, '/' => true, + '^' => true, '&' => true, '>' => true, '<' => true, + '=' => true, '>=' => true, '<=' => true, '<>' => true, + '|' => true, ':' => true + ); /** * Flag to determine how formula errors should be handled @@ -165,6 +180,19 @@ class PHPExcel_Calculation { */ public $writeDebugLog = false; + /** + * Flag to determine whether a debug log should be echoed by the calculation engine + * If true, then a debug log will be echoed + * If false, then a debug log will not be echoed + * A debug log can only be echoed if it is generated + * + * @access public + * @var boolean + * + */ + public $echoDebugLog = false; + + /** * An array of the nested cell references accessed by the calculation engine, used for the debug log * @@ -187,21 +215,24 @@ class PHPExcel_Calculation { public $cyclicFormulaCount = 0; + private $_savedPrecision = 12; + + private static $_localeLanguage = 'en_us'; // US English (default locale) private static $_validLocaleLanguages = array( 'en' // English (default language) ); private static $_localeArgumentSeparator = ','; private static $_localeFunctions = array(); - private static $_localeBoolean = array( 'TRUE' => 'TRUE', + public static $_localeBoolean = array( 'TRUE' => 'TRUE', 'FALSE' => 'FALSE', 'NULL' => 'NULL' ); // Constant conversion from text name/value to actual (datatyped) value - private static $_ExcelConstants = array('TRUE' => True, - 'FALSE' => False, - 'NULL' => Null + private static $_ExcelConstants = array('TRUE' => true, + 'FALSE' => false, + 'NULL' => null ); // PHPExcel functions @@ -211,11 +242,11 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'ACCRINT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::ACCRINT', + 'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINT', 'argumentCount' => '4-7' ), 'ACCRINTM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::ACCRINTM', + 'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINTM', 'argumentCount' => '3-5' ), 'ACOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -227,19 +258,19 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'ADDRESS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::CELL_ADDRESS', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::CELL_ADDRESS', 'argumentCount' => '2-5' ), 'AMORDEGRC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::AMORDEGRC', + 'functionCall' => 'PHPExcel_Calculation_Financial::AMORDEGRC', 'argumentCount' => '6,7' ), 'AMORLINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::AMORLINC', + 'functionCall' => 'PHPExcel_Calculation_Financial::AMORLINC', 'argumentCount' => '6,7' ), 'AND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_AND', + 'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_AND', 'argumentCount' => '1+' ), 'AREAS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, @@ -263,7 +294,7 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'ATAN2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::REVERSE_ATAN2', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::ATAN2', 'argumentCount' => '2' ), 'ATANH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -271,19 +302,19 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'AVEDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::AVEDEV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::AVEDEV', 'argumentCount' => '1+' ), 'AVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::AVERAGE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGE', 'argumentCount' => '1+' ), 'AVERAGEA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::AVERAGEA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEA', 'argumentCount' => '1+' ), 'AVERAGEIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEIF', 'argumentCount' => '2,3' ), 'AVERAGEIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -295,47 +326,47 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'BESSELI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::BESSELI', + 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELI', 'argumentCount' => '2' ), 'BESSELJ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::BESSELJ', + 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELJ', 'argumentCount' => '2' ), 'BESSELK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::BESSELK', + 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELK', 'argumentCount' => '2' ), 'BESSELY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::BESSELY', + 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELY', 'argumentCount' => '2' ), 'BETADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::BETADIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::BETADIST', 'argumentCount' => '3-5' ), 'BETAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::BETAINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::BETAINV', 'argumentCount' => '3-5' ), 'BIN2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::BINTODEC', + 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTODEC', 'argumentCount' => '1' ), 'BIN2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::BINTOHEX', + 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOHEX', 'argumentCount' => '1,2' ), 'BIN2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::BINTOOCT', + 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOOCT', 'argumentCount' => '1,2' ), 'BINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::BINOMDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::BINOMDIST', 'argumentCount' => '4' ), 'CEILING' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::CEILING', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::CEILING', 'argumentCount' => '2' ), 'CELL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, @@ -343,15 +374,15 @@ class PHPExcel_Calculation { 'argumentCount' => '1,2' ), 'CHAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::CHARACTER', + 'functionCall' => 'PHPExcel_Calculation_TextData::CHARACTER', 'argumentCount' => '1' ), 'CHIDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CHIDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::CHIDIST', 'argumentCount' => '2' ), 'CHIINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CHIINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::CHIINV', 'argumentCount' => '2' ), 'CHITEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -359,48 +390,48 @@ class PHPExcel_Calculation { 'argumentCount' => '2' ), 'CHOOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::CHOOSE', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::CHOOSE', 'argumentCount' => '2+' ), 'CLEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::TRIMNONPRINTABLE', + 'functionCall' => 'PHPExcel_Calculation_TextData::TRIMNONPRINTABLE', 'argumentCount' => '1' ), 'CODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::ASCIICODE', + 'functionCall' => 'PHPExcel_Calculation_TextData::ASCIICODE', 'argumentCount' => '1' ), 'COLUMN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::COLUMN', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMN', 'argumentCount' => '-1', 'passByReference' => array(true) ), 'COLUMNS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::COLUMNS', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMNS', 'argumentCount' => '1' ), 'COMBIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::COMBIN', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::COMBIN', 'argumentCount' => '2' ), 'COMPLEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::COMPLEX', + 'functionCall' => 'PHPExcel_Calculation_Engineering::COMPLEX', 'argumentCount' => '2,3' ), 'CONCATENATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::CONCATENATE', + 'functionCall' => 'PHPExcel_Calculation_TextData::CONCATENATE', 'argumentCount' => '1+' ), 'CONFIDENCE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CONFIDENCE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::CONFIDENCE', 'argumentCount' => '3' ), 'CONVERT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::CONVERTUOM', + 'functionCall' => 'PHPExcel_Calculation_Engineering::CONVERTUOM', 'argumentCount' => '3' ), 'CORREL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CORREL', + 'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL', 'argumentCount' => '2' ), 'COS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -412,19 +443,19 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'COUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUNT', + 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNT', 'argumentCount' => '1+' ), 'COUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUNTA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTA', 'argumentCount' => '1+' ), 'COUNTBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUNTBLANK', + 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTBLANK', 'argumentCount' => '1' ), 'COUNTIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUNTIF', + 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTIF', 'argumentCount' => '2' ), 'COUNTIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -432,35 +463,35 @@ class PHPExcel_Calculation { 'argumentCount' => '2' ), 'COUPDAYBS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUPDAYBS', + 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYBS', 'argumentCount' => '3,4' ), 'COUPDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUPDAYS', + 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYS', 'argumentCount' => '3,4' ), 'COUPDAYSNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUPDAYSNC', + 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYSNC', 'argumentCount' => '3,4' ), 'COUPNCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUPNCD', + 'functionCall' => 'PHPExcel_Calculation_Financial::COUPNCD', 'argumentCount' => '3,4' ), 'COUPNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUPNUM', + 'functionCall' => 'PHPExcel_Calculation_Financial::COUPNUM', 'argumentCount' => '3,4' ), 'COUPPCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COUPPCD', + 'functionCall' => 'PHPExcel_Calculation_Financial::COUPPCD', 'argumentCount' => '3,4' ), 'COVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::COVAR', + 'functionCall' => 'PHPExcel_Calculation_Statistical::COVAR', 'argumentCount' => '2' ), 'CRITBINOM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CRITBINOM', + 'functionCall' => 'PHPExcel_Calculation_Statistical::CRITBINOM', 'argumentCount' => '3' ), 'CUBEKPIMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE, @@ -492,23 +523,23 @@ class PHPExcel_Calculation { 'argumentCount' => '?' ), 'CUMIPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CUMIPMT', + 'functionCall' => 'PHPExcel_Calculation_Financial::CUMIPMT', 'argumentCount' => '6' ), 'CUMPRINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CUMPRINC', + 'functionCall' => 'PHPExcel_Calculation_Financial::CUMPRINC', 'argumentCount' => '6' ), 'DATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DATE', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DATE', 'argumentCount' => '3' ), 'DATEDIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DATEDIF', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DATEDIF', 'argumentCount' => '2,3' ), 'DATEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DATEVALUE', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DATEVALUE', 'argumentCount' => '1' ), 'DAVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, @@ -516,39 +547,39 @@ class PHPExcel_Calculation { 'argumentCount' => '3' ), 'DAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DAYOFMONTH', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFMONTH', 'argumentCount' => '1' ), 'DAYS360' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DAYS360', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYS360', 'argumentCount' => '2,3' ), 'DB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DB', + 'functionCall' => 'PHPExcel_Calculation_Financial::DB', 'argumentCount' => '4,5' ), 'DCOUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DCOUNT', 'argumentCount' => '3' ), 'DCOUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DCOUNTA', 'argumentCount' => '3' ), 'DDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DDB', + 'functionCall' => 'PHPExcel_Calculation_Financial::DDB', 'argumentCount' => '4,5' ), 'DEC2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::DECTOBIN', + 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOBIN', 'argumentCount' => '1,2' ), 'DEC2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::DECTOHEX', + 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOHEX', 'argumentCount' => '1,2' ), 'DEC2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::DECTOOCT', + 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOOCT', 'argumentCount' => '1,2' ), 'DEGREES' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -556,55 +587,55 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'DELTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::DELTA', + 'functionCall' => 'PHPExcel_Calculation_Engineering::DELTA', 'argumentCount' => '1,2' ), 'DEVSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DEVSQ', + 'functionCall' => 'PHPExcel_Calculation_Statistical::DEVSQ', 'argumentCount' => '1+' ), 'DGET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DGET', 'argumentCount' => '3' ), 'DISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DISC', + 'functionCall' => 'PHPExcel_Calculation_Financial::DISC', 'argumentCount' => '4,5' ), 'DMAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DMAX', 'argumentCount' => '3' ), 'DMIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DMIN', 'argumentCount' => '3' ), 'DOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::DOLLAR', + 'functionCall' => 'PHPExcel_Calculation_TextData::DOLLAR', 'argumentCount' => '1,2' ), 'DOLLARDE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DOLLARDE', + 'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARDE', 'argumentCount' => '2' ), 'DOLLARFR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DOLLARFR', + 'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARFR', 'argumentCount' => '2' ), 'DPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DPRODUCT', 'argumentCount' => '3' ), 'DSTDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DSTDEV', 'argumentCount' => '3' ), 'DSTDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DSTDEVP', 'argumentCount' => '3' ), 'DSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DSUM', 'argumentCount' => '3' ), 'DURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, @@ -612,31 +643,31 @@ class PHPExcel_Calculation { 'argumentCount' => '5,6' ), 'DVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DVAR', 'argumentCount' => '3' ), 'DVARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Database::DVARP', 'argumentCount' => '3' ), 'EDATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::EDATE', + 'functionCall' => 'PHPExcel_Calculation_DateTime::EDATE', 'argumentCount' => '2' ), 'EFFECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::EFFECT', + 'functionCall' => 'PHPExcel_Calculation_Financial::EFFECT', 'argumentCount' => '2' ), 'EOMONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::EOMONTH', + 'functionCall' => 'PHPExcel_Calculation_DateTime::EOMONTH', 'argumentCount' => '2' ), 'ERF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::ERF', + 'functionCall' => 'PHPExcel_Calculation_Engineering::ERF', 'argumentCount' => '1,2' ), 'ERFC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::ERFC', + 'functionCall' => 'PHPExcel_Calculation_Engineering::ERFC', 'argumentCount' => '1' ), 'ERROR.TYPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, @@ -644,7 +675,7 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'EVEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::EVEN', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::EVEN', 'argumentCount' => '1' ), 'EXACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, @@ -656,19 +687,19 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'EXPONDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::EXPONDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::EXPONDIST', 'argumentCount' => '3' ), 'FACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::FACT', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::FACT', 'argumentCount' => '1' ), 'FACTDOUBLE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::FACTDOUBLE', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::FACTDOUBLE', 'argumentCount' => '1' ), 'FALSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_FALSE', + 'functionCall' => 'PHPExcel_Calculation_Logical::FALSE', 'argumentCount' => '0' ), 'FDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -676,11 +707,11 @@ class PHPExcel_Calculation { 'argumentCount' => '3' ), 'FIND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHSENSITIVE', + 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE', 'argumentCount' => '2,3' ), 'FINDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHSENSITIVE', + 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE', 'argumentCount' => '2,3' ), 'FINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -688,23 +719,23 @@ class PHPExcel_Calculation { 'argumentCount' => '3' ), 'FISHER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::FISHER', + 'functionCall' => 'PHPExcel_Calculation_Statistical::FISHER', 'argumentCount' => '1' ), 'FISHERINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::FISHERINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::FISHERINV', 'argumentCount' => '1' ), 'FIXED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::FIXEDFORMAT', + 'functionCall' => 'PHPExcel_Calculation_TextData::FIXEDFORMAT', 'argumentCount' => '1-3' ), 'FLOOR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::FLOOR', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::FLOOR', 'argumentCount' => '2' ), 'FORECAST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::FORECAST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::FORECAST', 'argumentCount' => '3' ), 'FREQUENCY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -716,35 +747,35 @@ class PHPExcel_Calculation { 'argumentCount' => '2' ), 'FV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::FV', + 'functionCall' => 'PHPExcel_Calculation_Financial::FV', 'argumentCount' => '3-5' ), 'FVSCHEDULE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::FVSCHEDULE', + 'functionCall' => 'PHPExcel_Calculation_Financial::FVSCHEDULE', 'argumentCount' => '2' ), 'GAMMADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::GAMMADIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMADIST', 'argumentCount' => '4' ), 'GAMMAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::GAMMAINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMAINV', 'argumentCount' => '3' ), 'GAMMALN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::GAMMALN', + 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMALN', 'argumentCount' => '1' ), 'GCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::GCD', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::GCD', 'argumentCount' => '1+' ), 'GEOMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::GEOMEAN', + 'functionCall' => 'PHPExcel_Calculation_Statistical::GEOMEAN', 'argumentCount' => '1+' ), 'GESTEP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::GESTEP', + 'functionCall' => 'PHPExcel_Calculation_Engineering::GESTEP', 'argumentCount' => '1,2' ), 'GETPIVOTDATA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, @@ -752,23 +783,23 @@ class PHPExcel_Calculation { 'argumentCount' => '2+' ), 'GROWTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::GROWTH', + 'functionCall' => 'PHPExcel_Calculation_Statistical::GROWTH', 'argumentCount' => '1-4' ), 'HARMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::HARMEAN', + 'functionCall' => 'PHPExcel_Calculation_Statistical::HARMEAN', 'argumentCount' => '1+' ), 'HEX2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::HEXTOBIN', + 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOBIN', 'argumentCount' => '1,2' ), 'HEX2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::HEXTODEC', + 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTODEC', 'argumentCount' => '1' ), 'HEX2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::HEXTOOCT', + 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOOCT', 'argumentCount' => '1,2' ), 'HLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, @@ -776,100 +807,100 @@ class PHPExcel_Calculation { 'argumentCount' => '3,4' ), 'HOUR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::HOUROFDAY', + 'functionCall' => 'PHPExcel_Calculation_DateTime::HOUROFDAY', 'argumentCount' => '1' ), 'HYPERLINK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::HYPERLINK', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::HYPERLINK', 'argumentCount' => '1,2', 'passCellReference'=> true ), 'HYPGEOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::HYPGEOMDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::HYPGEOMDIST', 'argumentCount' => '4' ), 'IF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STATEMENT_IF', + 'functionCall' => 'PHPExcel_Calculation_Logical::STATEMENT_IF', 'argumentCount' => '1-3' ), 'IFERROR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STATEMENT_IFERROR', + 'functionCall' => 'PHPExcel_Calculation_Logical::IFERROR', 'argumentCount' => '2' ), 'IMABS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMABS', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMABS', 'argumentCount' => '1' ), 'IMAGINARY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMAGINARY', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMAGINARY', 'argumentCount' => '1' ), 'IMARGUMENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMARGUMENT', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMARGUMENT', 'argumentCount' => '1' ), 'IMCONJUGATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMCONJUGATE', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMCONJUGATE', 'argumentCount' => '1' ), 'IMCOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMCOS', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMCOS', 'argumentCount' => '1' ), 'IMDIV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMDIV', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMDIV', 'argumentCount' => '2' ), 'IMEXP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMEXP', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMEXP', 'argumentCount' => '1' ), 'IMLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMLN', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLN', 'argumentCount' => '1' ), 'IMLOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMLOG10', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG10', 'argumentCount' => '1' ), 'IMLOG2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMLOG2', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG2', 'argumentCount' => '1' ), 'IMPOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMPOWER', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMPOWER', 'argumentCount' => '2' ), 'IMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMPRODUCT', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMPRODUCT', 'argumentCount' => '1+' ), 'IMREAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMREAL', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMREAL', 'argumentCount' => '1' ), 'IMSIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMSIN', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSIN', 'argumentCount' => '1' ), 'IMSQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMSQRT', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSQRT', 'argumentCount' => '1' ), 'IMSUB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMSUB', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUB', 'argumentCount' => '2' ), 'IMSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::IMSUM', + 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUM', 'argumentCount' => '1+' ), 'INDEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::INDEX', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::INDEX', 'argumentCount' => '1-4' ), 'INDIRECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::INDIRECT', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::INDIRECT', 'argumentCount' => '1,2', 'passCellReference'=> true ), @@ -878,23 +909,23 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'INT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::INTVALUE', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::INT', 'argumentCount' => '1' ), 'INTERCEPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::INTERCEPT', + 'functionCall' => 'PHPExcel_Calculation_Statistical::INTERCEPT', 'argumentCount' => '2' ), 'INTRATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::INTRATE', + 'functionCall' => 'PHPExcel_Calculation_Financial::INTRATE', 'argumentCount' => '4,5' ), 'IPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::IPMT', + 'functionCall' => 'PHPExcel_Calculation_Financial::IPMT', 'argumentCount' => '4-6' ), 'IRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::IRR', + 'functionCall' => 'PHPExcel_Calculation_Financial::IRR', 'argumentCount' => '1,2' ), 'ISBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, @@ -934,7 +965,7 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'ISPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::ISPMT', + 'functionCall' => 'PHPExcel_Calculation_Financial::ISPMT', 'argumentCount' => '4' ), 'ISREF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, @@ -950,35 +981,35 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'KURT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::KURT', + 'functionCall' => 'PHPExcel_Calculation_Statistical::KURT', 'argumentCount' => '1+' ), 'LARGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LARGE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::LARGE', 'argumentCount' => '2' ), 'LCM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::LCM', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::LCM', 'argumentCount' => '1+' ), 'LEFT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::LEFT', + 'functionCall' => 'PHPExcel_Calculation_TextData::LEFT', 'argumentCount' => '1,2' ), 'LEFTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::LEFT', + 'functionCall' => 'PHPExcel_Calculation_TextData::LEFT', 'argumentCount' => '1,2' ), 'LEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::STRINGLENGTH', + 'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH', 'argumentCount' => '1' ), 'LENB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::STRINGLENGTH', + 'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH', 'argumentCount' => '1' ), 'LINEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LINEST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::LINEST', 'argumentCount' => '1-4' ), 'LN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -986,7 +1017,7 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'LOG' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOG_BASE', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::LOG_BASE', 'argumentCount' => '1,2' ), 'LOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -994,43 +1025,43 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'LOGEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGEST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGEST', 'argumentCount' => '1-4' ), 'LOGINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGINV', 'argumentCount' => '3' ), 'LOGNORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGNORMDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGNORMDIST', 'argumentCount' => '3' ), 'LOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOOKUP', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::LOOKUP', 'argumentCount' => '2,3' ), 'LOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOWERCASE', + 'functionCall' => 'PHPExcel_Calculation_TextData::LOWERCASE', 'argumentCount' => '1' ), 'MATCH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::MATCH', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::MATCH', 'argumentCount' => '2,3' ), 'MAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::MAX', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MAX', 'argumentCount' => '1+' ), 'MAXA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::MAXA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MAXA', 'argumentCount' => '1+' ), 'MAXIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MAXIF', 'argumentCount' => '2+' ), 'MDETERM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::MDETERM', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::MDETERM', 'argumentCount' => '1' ), 'MDURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, @@ -1038,7 +1069,7 @@ class PHPExcel_Calculation { 'argumentCount' => '5,6' ), 'MEDIAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::MEDIAN', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MEDIAN', 'argumentCount' => '1+' ), 'MEDIANIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -1046,59 +1077,59 @@ class PHPExcel_Calculation { 'argumentCount' => '2+' ), 'MID' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::MID', + 'functionCall' => 'PHPExcel_Calculation_TextData::MID', 'argumentCount' => '3' ), 'MIDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::MID', + 'functionCall' => 'PHPExcel_Calculation_TextData::MID', 'argumentCount' => '3' ), 'MIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::MIN', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MIN', 'argumentCount' => '1+' ), 'MINA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::MINA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MINA', 'argumentCount' => '1+' ), 'MINIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MINIF', 'argumentCount' => '2+' ), 'MINUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::MINUTEOFHOUR', + 'functionCall' => 'PHPExcel_Calculation_DateTime::MINUTEOFHOUR', 'argumentCount' => '1' ), 'MINVERSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::MINVERSE', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::MINVERSE', 'argumentCount' => '1' ), 'MIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::MIRR', + 'functionCall' => 'PHPExcel_Calculation_Financial::MIRR', 'argumentCount' => '3' ), 'MMULT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::MMULT', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::MMULT', 'argumentCount' => '2' ), 'MOD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::MOD', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::MOD', 'argumentCount' => '2' ), 'MODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::MODE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::MODE', 'argumentCount' => '1+' ), 'MONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::MONTHOFYEAR', + 'functionCall' => 'PHPExcel_Calculation_DateTime::MONTHOFYEAR', 'argumentCount' => '1' ), 'MROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::MROUND', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::MROUND', 'argumentCount' => '2' ), 'MULTINOMIAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::MULTINOMIAL', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::MULTINOMIAL', 'argumentCount' => '1+' ), 'N' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION, @@ -1110,63 +1141,63 @@ class PHPExcel_Calculation { 'argumentCount' => '0' ), 'NEGBINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NEGBINOMDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::NEGBINOMDIST', 'argumentCount' => '3' ), 'NETWORKDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::NETWORKDAYS', + 'functionCall' => 'PHPExcel_Calculation_DateTime::NETWORKDAYS', 'argumentCount' => '2+' ), 'NOMINAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NOMINAL', + 'functionCall' => 'PHPExcel_Calculation_Financial::NOMINAL', 'argumentCount' => '2' ), 'NORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NORMDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMDIST', 'argumentCount' => '4' ), 'NORMINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NORMINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMINV', 'argumentCount' => '3' ), 'NORMSDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NORMSDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSDIST', 'argumentCount' => '1' ), 'NORMSINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NORMSINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSINV', 'argumentCount' => '1' ), 'NOT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_NOT', + 'functionCall' => 'PHPExcel_Calculation_Logical::NOT', 'argumentCount' => '1' ), 'NOW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DATETIMENOW', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DATETIMENOW', 'argumentCount' => '0' ), 'NPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NPER', + 'functionCall' => 'PHPExcel_Calculation_Financial::NPER', 'argumentCount' => '3-5' ), 'NPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::NPV', + 'functionCall' => 'PHPExcel_Calculation_Financial::NPV', 'argumentCount' => '2+' ), 'OCT2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::OCTTOBIN', + 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOBIN', 'argumentCount' => '1,2' ), 'OCT2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::OCTTODEC', + 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTODEC', 'argumentCount' => '1' ), 'OCT2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING, - 'functionCall' => 'PHPExcel_Calculation_Functions::OCTTOHEX', + 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOHEX', 'argumentCount' => '1,2' ), 'ODD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::ODD', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::ODD', 'argumentCount' => '1' ), 'ODDFPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, @@ -1186,29 +1217,29 @@ class PHPExcel_Calculation { 'argumentCount' => '7,8' ), 'OFFSET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::OFFSET', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::OFFSET', 'argumentCount' => '3,5', 'passCellReference'=> true, 'passByReference' => array(true) ), 'OR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_OR', + 'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_OR', 'argumentCount' => '1+' ), 'PEARSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::CORREL', + 'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL', 'argumentCount' => '2' ), 'PERCENTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PERCENTILE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTILE', 'argumentCount' => '2' ), 'PERCENTRANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PERCENTRANK', + 'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTRANK', 'argumentCount' => '2,3' ), 'PERMUT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PERMUT', + 'functionCall' => 'PHPExcel_Calculation_Statistical::PERMUT', 'argumentCount' => '2' ), 'PHONETIC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, @@ -1220,31 +1251,31 @@ class PHPExcel_Calculation { 'argumentCount' => '0' ), 'PMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PMT', + 'functionCall' => 'PHPExcel_Calculation_Financial::PMT', 'argumentCount' => '3-5' ), 'POISSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::POISSON', + 'functionCall' => 'PHPExcel_Calculation_Statistical::POISSON', 'argumentCount' => '3' ), 'POWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::POWER', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::POWER', 'argumentCount' => '2' ), 'PPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PPMT', + 'functionCall' => 'PHPExcel_Calculation_Financial::PPMT', 'argumentCount' => '4-6' ), 'PRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PRICE', + 'functionCall' => 'PHPExcel_Calculation_Financial::PRICE', 'argumentCount' => '6,7' ), 'PRICEDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PRICEDISC', + 'functionCall' => 'PHPExcel_Calculation_Financial::PRICEDISC', 'argumentCount' => '4,5' ), 'PRICEMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PRICEMAT', + 'functionCall' => 'PHPExcel_Calculation_Financial::PRICEMAT', 'argumentCount' => '5,6' ), 'PROB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -1252,23 +1283,23 @@ class PHPExcel_Calculation { 'argumentCount' => '3,4' ), 'PRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::PRODUCT', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::PRODUCT', 'argumentCount' => '1+' ), 'PROPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::PROPERCASE', + 'functionCall' => 'PHPExcel_Calculation_TextData::PROPERCASE', 'argumentCount' => '1' ), 'PV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::PV', + 'functionCall' => 'PHPExcel_Calculation_Financial::PV', 'argumentCount' => '3-5' ), 'QUARTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::QUARTILE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::QUARTILE', 'argumentCount' => '2' ), 'QUOTIENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::QUOTIENT', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::QUOTIENT', 'argumentCount' => '2' ), 'RADIANS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -1276,31 +1307,31 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'RAND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::RAND', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND', 'argumentCount' => '0' ), 'RANDBETWEEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::RAND', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND', 'argumentCount' => '2' ), 'RANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::RANK', + 'functionCall' => 'PHPExcel_Calculation_Statistical::RANK', 'argumentCount' => '2,3' ), 'RATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::RATE', + 'functionCall' => 'PHPExcel_Calculation_Financial::RATE', 'argumentCount' => '3-6' ), 'RECEIVED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::RECEIVED', + 'functionCall' => 'PHPExcel_Calculation_Financial::RECEIVED', 'argumentCount' => '4-5' ), 'REPLACE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::REPLACE', + 'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE', 'argumentCount' => '4' ), 'REPLACEB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::REPLACE', + 'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE', 'argumentCount' => '4' ), 'REPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, @@ -1308,15 +1339,15 @@ class PHPExcel_Calculation { 'argumentCount' => '2' ), 'RIGHT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::RIGHT', + 'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT', 'argumentCount' => '1,2' ), 'RIGHTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::RIGHT', + 'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT', 'argumentCount' => '1,2' ), 'ROMAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::ROMAN', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROMAN', 'argumentCount' => '1,2' ), 'ROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -1324,24 +1355,24 @@ class PHPExcel_Calculation { 'argumentCount' => '2' ), 'ROUNDDOWN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::ROUNDDOWN', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDDOWN', 'argumentCount' => '2' ), 'ROUNDUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::ROUNDUP', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDUP', 'argumentCount' => '2' ), 'ROW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::ROW', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROW', 'argumentCount' => '-1', 'passByReference' => array(true) ), 'ROWS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::ROWS', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROWS', 'argumentCount' => '1' ), 'RSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::RSQ', + 'functionCall' => 'PHPExcel_Calculation_Statistical::RSQ', 'argumentCount' => '2' ), 'RTD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, @@ -1349,23 +1380,23 @@ class PHPExcel_Calculation { 'argumentCount' => '1+' ), 'SEARCH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHINSENSITIVE', + 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE', 'argumentCount' => '2,3' ), 'SEARCHB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHINSENSITIVE', + 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE', 'argumentCount' => '2,3' ), 'SECOND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::SECONDOFMINUTE', + 'functionCall' => 'PHPExcel_Calculation_DateTime::SECONDOFMINUTE', 'argumentCount' => '1' ), 'SERIESSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SERIESSUM', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SERIESSUM', 'argumentCount' => '4' ), 'SIGN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SIGN', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SIGN', 'argumentCount' => '1' ), 'SIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -1377,19 +1408,19 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'SKEW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::SKEW', + 'functionCall' => 'PHPExcel_Calculation_Statistical::SKEW', 'argumentCount' => '1+' ), 'SLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::SLN', + 'functionCall' => 'PHPExcel_Calculation_Financial::SLN', 'argumentCount' => '3' ), 'SLOPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::SLOPE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::SLOPE', 'argumentCount' => '2' ), 'SMALL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::SMALL', + 'functionCall' => 'PHPExcel_Calculation_Statistical::SMALL', 'argumentCount' => '2' ), 'SQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -1397,47 +1428,47 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'SQRTPI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SQRTPI', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SQRTPI', 'argumentCount' => '1' ), 'STANDARDIZE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STANDARDIZE', + 'functionCall' => 'PHPExcel_Calculation_Statistical::STANDARDIZE', 'argumentCount' => '3' ), 'STDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STDEV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEV', 'argumentCount' => '1+' ), 'STDEVA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STDEVA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVA', 'argumentCount' => '1+' ), 'STDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STDEVP', + 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVP', 'argumentCount' => '1+' ), 'STDEVPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STDEVPA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVPA', 'argumentCount' => '1+' ), 'STEYX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::STEYX', + 'functionCall' => 'PHPExcel_Calculation_Statistical::STEYX', 'argumentCount' => '2' ), 'SUBSTITUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUBSTITUTE', + 'functionCall' => 'PHPExcel_Calculation_TextData::SUBSTITUTE', 'argumentCount' => '3,4' ), 'SUBTOTAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUBTOTAL', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUBTOTAL', 'argumentCount' => '2+' ), 'SUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUM', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUM', 'argumentCount' => '1+' ), 'SUMIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUMIF', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMIF', 'argumentCount' => '2,3' ), 'SUMIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -1445,31 +1476,31 @@ class PHPExcel_Calculation { 'argumentCount' => '?' ), 'SUMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUMPRODUCT', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMPRODUCT', 'argumentCount' => '1+' ), 'SUMSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUMSQ', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMSQ', 'argumentCount' => '1+' ), 'SUMX2MY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUMX2MY2', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2MY2', 'argumentCount' => '2' ), 'SUMX2PY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUMX2PY2', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2PY2', 'argumentCount' => '2' ), 'SUMXMY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::SUMXMY2', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMXMY2', 'argumentCount' => '2' ), 'SYD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::SYD', + 'functionCall' => 'PHPExcel_Calculation_Financial::SYD', 'argumentCount' => '4' ), 'T' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::RETURNSTRING', + 'functionCall' => 'PHPExcel_Calculation_TextData::RETURNSTRING', 'argumentCount' => '1' ), 'TAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, @@ -1481,63 +1512,63 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'TBILLEQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::TBILLEQ', + 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLEQ', 'argumentCount' => '3' ), 'TBILLPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::TBILLPRICE', + 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLPRICE', 'argumentCount' => '3' ), 'TBILLYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::TBILLYIELD', + 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLYIELD', 'argumentCount' => '3' ), 'TDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::TDIST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::TDIST', 'argumentCount' => '3' ), 'TEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::TEXTFORMAT', + 'functionCall' => 'PHPExcel_Calculation_TextData::TEXTFORMAT', 'argumentCount' => '2' ), 'TIME' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::TIME', + 'functionCall' => 'PHPExcel_Calculation_DateTime::TIME', 'argumentCount' => '3' ), 'TIMEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::TIMEVALUE', + 'functionCall' => 'PHPExcel_Calculation_DateTime::TIMEVALUE', 'argumentCount' => '1' ), 'TINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::TINV', + 'functionCall' => 'PHPExcel_Calculation_Statistical::TINV', 'argumentCount' => '2' ), 'TODAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DATENOW', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DATENOW', 'argumentCount' => '0' ), 'TRANSPOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::TRANSPOSE', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::TRANSPOSE', 'argumentCount' => '1' ), 'TREND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::TREND', + 'functionCall' => 'PHPExcel_Calculation_Statistical::TREND', 'argumentCount' => '1-4' ), 'TRIM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::TRIMSPACES', + 'functionCall' => 'PHPExcel_Calculation_TextData::TRIMSPACES', 'argumentCount' => '1' ), 'TRIMMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::TRIMMEAN', + 'functionCall' => 'PHPExcel_Calculation_Statistical::TRIMMEAN', 'argumentCount' => '2' ), 'TRUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_TRUE', + 'functionCall' => 'PHPExcel_Calculation_Logical::TRUE', 'argumentCount' => '0' ), 'TRUNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'PHPExcel_Calculation_Functions::TRUNC', + 'functionCall' => 'PHPExcel_Calculation_MathTrig::TRUNC', 'argumentCount' => '1,2' ), 'TTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, @@ -1549,7 +1580,7 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'UPPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'PHPExcel_Calculation_Functions::UPPERCASE', + 'functionCall' => 'PHPExcel_Calculation_TextData::UPPERCASE', 'argumentCount' => '1' ), 'USDOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, @@ -1561,19 +1592,19 @@ class PHPExcel_Calculation { 'argumentCount' => '1' ), 'VAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::VARFunc', + 'functionCall' => 'PHPExcel_Calculation_Statistical::VARFunc', 'argumentCount' => '1+' ), 'VARA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::VARA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::VARA', 'argumentCount' => '1+' ), 'VARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::VARP', + 'functionCall' => 'PHPExcel_Calculation_Statistical::VARP', 'argumentCount' => '1+' ), 'VARPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::VARPA', + 'functionCall' => 'PHPExcel_Calculation_Statistical::VARPA', 'argumentCount' => '1+' ), 'VDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, @@ -1585,39 +1616,39 @@ class PHPExcel_Calculation { 'argumentCount' => '0' ), 'VLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => 'PHPExcel_Calculation_Functions::VLOOKUP', + 'functionCall' => 'PHPExcel_Calculation_LookupRef::VLOOKUP', 'argumentCount' => '3,4' ), 'WEEKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::DAYOFWEEK', + 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFWEEK', 'argumentCount' => '1,2' ), 'WEEKNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::WEEKOFYEAR', + 'functionCall' => 'PHPExcel_Calculation_DateTime::WEEKOFYEAR', 'argumentCount' => '1,2' ), 'WEIBULL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::WEIBULL', + 'functionCall' => 'PHPExcel_Calculation_Statistical::WEIBULL', 'argumentCount' => '4' ), 'WORKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::WORKDAY', + 'functionCall' => 'PHPExcel_Calculation_DateTime::WORKDAY', 'argumentCount' => '2+' ), 'XIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::XIRR', + 'functionCall' => 'PHPExcel_Calculation_Financial::XIRR', 'argumentCount' => '2,3' ), 'XNPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::XNPV', + 'functionCall' => 'PHPExcel_Calculation_Financial::XNPV', 'argumentCount' => '3' ), 'YEAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::YEAR', + 'functionCall' => 'PHPExcel_Calculation_DateTime::YEAR', 'argumentCount' => '1' ), 'YEARFRAC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME, - 'functionCall' => 'PHPExcel_Calculation_Functions::YEARFRAC', + 'functionCall' => 'PHPExcel_Calculation_DateTime::YEARFRAC', 'argumentCount' => '2,3' ), 'YIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, @@ -1625,15 +1656,15 @@ class PHPExcel_Calculation { 'argumentCount' => '6,7' ), 'YIELDDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::YIELDDISC', + 'functionCall' => 'PHPExcel_Calculation_Financial::YIELDDISC', 'argumentCount' => '4,5' ), 'YIELDMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::YIELDMAT', + 'functionCall' => 'PHPExcel_Calculation_Financial::YIELDMAT', 'argumentCount' => '5,6' ), 'ZTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL, - 'functionCall' => 'PHPExcel_Calculation_Functions::ZTEST', + 'functionCall' => 'PHPExcel_Calculation_Statistical::ZTEST', 'argumentCount' => '2-3' ) ); @@ -1649,7 +1680,7 @@ class PHPExcel_Calculation { - function __construct() { + private function __construct() { $localeFileDirectory = PHPEXCEL_ROOT.'PHPExcel/locale/'; foreach (glob($localeFileDirectory.'/*',GLOB_ONLYDIR) as $filename) { $filename = substr($filename,strlen($localeFileDirectory)+1); @@ -1657,9 +1688,19 @@ class PHPExcel_Calculation { self::$_validLocaleLanguages[] = $filename; } } + + $setPrecision = (PHP_INT_SIZE == 4) ? 12 : 16; + $this->_savedPrecision = ini_get('precision'); + if ($this->_savedPrecision < $setPrecision) { + ini_set('precision',$setPrecision); + } } // function __construct() + public function __destruct() { + ini_set('precision',$this->_savedPrecision); + } + /** * Get an instance of this class * @@ -1675,6 +1716,20 @@ class PHPExcel_Calculation { } // function getInstance() + /** + * Flush the calculation cache for any existing instance of this class + * but only if a PHPExcel_Calculation instance exists + * + * @access public + * @return null + */ + public static function flushInstance() { + if (isset(self::$_instance) && !is_null(self::$_instance)) { + self::$_instance->clearCalculationCache(); + } + } // function flushInstance() + + /** * __clone implementation. Cloning should not be allowed in a Singleton! * @@ -1686,6 +1741,26 @@ class PHPExcel_Calculation { } // function __clone() + /** + * Return the locale-specific translation of TRUE + * + * @access public + * @return string locale-specific translation of TRUE + */ + public static function getTRUE() { + return self::$_localeBoolean['TRUE']; + } + + /** + * Return the locale-specific translation of FALSE + * + * @access public + * @return string locale-specific translation of FALSE + */ + public static function getFALSE() { + return self::$_localeBoolean['FALSE']; + } + /** * Set the Array Return Type (Array or Value of first element in the array) * @@ -1698,9 +1773,9 @@ class PHPExcel_Calculation { ($returnType == self::RETURN_ARRAY_AS_ERROR) || ($returnType == self::RETURN_ARRAY_AS_ARRAY)) { self::$returnArrayAsType = $returnType; - return True; + return true; } - return False; + return false; } // function setExcelCalendar() @@ -1777,7 +1852,7 @@ class PHPExcel_Calculation { * * @param float $pValue */ - public function setCalculationCacheExpirationTime($pValue = 2.5) { + public function setCalculationCacheExpirationTime($pValue = 15) { self::$_calculationCacheExpirationTime = $pValue; } // function setCalculationCacheExpirationTime() @@ -1862,7 +1937,7 @@ class PHPExcel_Calculation { } self::$functionReplaceFromExcel = self::$functionReplaceToExcel = - self::$functionReplaceFromLocale = self::$functionReplaceToLocale = NULL; + self::$functionReplaceFromLocale = self::$functionReplaceToLocale = null; self::$_localeLanguage = $locale; return true; } @@ -1876,9 +1951,9 @@ class PHPExcel_Calculation { for ($i = 0; $i < $strlen; ++$i) { $chr = mb_substr($formula,$i,1); switch ($chr) { - case '{' : $inBraces = True; + case '{' : $inBraces = true; break; - case '}' : $inBraces = False; + case '}' : $inBraces = false; break; case $fromSeparator : if (!$inBraces) { @@ -1890,17 +1965,18 @@ class PHPExcel_Calculation { } private static function _translateFormula($from,$to,$formula,$fromSeparator,$toSeparator) { - $inBraces = False; // Convert any Excel function names to the required language if (self::$_localeLanguage !== 'en_us') { + $inBraces = false; // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators if (strpos($formula,'"') !== false) { // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded // the formula $temp = explode('"',$formula); - foreach($temp as $i => &$value) { - // Only count/replace in alternate array entries - if (($i % 2) == 0) { + $i = false; + foreach($temp as &$value) { + // Only count/replace in alternating array entries + if ($i = !$i) { $value = preg_replace($from,$to,$value); $value = self::_translateSeparator($fromSeparator,$toSeparator,$value,$inBraces); } @@ -1911,15 +1987,15 @@ class PHPExcel_Calculation { } else { // If there's no quoted strings, then we do a simple count/replace $formula = preg_replace($from,$to,$formula); - $formula = self::_translateSeparator($fromSeparator,$toSeparator,$formula); + $formula = self::_translateSeparator($fromSeparator,$toSeparator,$formula,$inBraces); } } return $formula; } - private static $functionReplaceFromExcel = NULL; - private static $functionReplaceToLocale = NULL; + private static $functionReplaceFromExcel = null; + private static $functionReplaceToLocale = null; public function _translateFormulaToLocale($formula) { if (is_null(self::$functionReplaceFromExcel)) { @@ -1947,8 +2023,8 @@ class PHPExcel_Calculation { } // function _translateFormulaToLocale() - private static $functionReplaceFromLocale = NULL; - private static $functionReplaceToExcel = NULL; + private static $functionReplaceFromLocale = null; + private static $functionReplaceToExcel = null; public function _translateFormulaToEnglish($formula) { if (is_null(self::$functionReplaceFromLocale)) { @@ -2022,7 +2098,7 @@ class PHPExcel_Calculation { */ public static function _unwrapResult($value) { if (is_string($value)) { - if ((strlen($value) > 0) && ($value{0} == '"') && (substr($value,-1) == '"')) { + if ((isset($value{0})) && ($value{0} == '"') && (substr($value,-1) == '"')) { return substr($value,1,-1); } // Convert numeric errors to NaN error @@ -2130,10 +2206,9 @@ class PHPExcel_Calculation { // Basic validation that this is indeed a formula // We return an empty array if not $formula = trim($formula); - if ((strlen($formula) == 0) || ($formula{0} != '=')) return array(); - $formula = trim(substr($formula,1)); - $formulaLength = strlen($formula); - if ($formulaLength < 1) return array(); + if ((!isset($formula{0})) || ($formula{0} != '=')) return array(); + $formula = ltrim(substr($formula,1)); + if (!isset($formula{0})) return array(); // Parse the formula and return the token stack return $this->_parseFormula($formula); @@ -2187,11 +2262,10 @@ class PHPExcel_Calculation { // We simply return the "cell value" (formula) if not $formula = trim($formula); if ($formula{0} != '=') return self::_wrapResult($formula); - $formula = trim(substr($formula,1)); - $formulaLength = strlen($formula); - if ($formulaLength < 1) return self::_wrapResult($formula); + $formula = ltrim(substr($formula,1)); + if (!isset($formula{0})) return self::_wrapResult($formula); - $wsTitle = 'Wrk'; + $wsTitle = "\x00Wrk"; if (!is_null($pCell)) { $pCellParent = $pCell->getParent(); if (!is_null($pCellParent)) { @@ -2207,7 +2281,7 @@ class PHPExcel_Calculation { // echo 'Value is in cache
'; $this->_writeDebug('Testing cache value for cell '.$cellID); // Is cache still valid? - if ((time() + microtime(true)) - self::$_calculationCache[$wsTitle][$cellID]['time'] < self::$_calculationCacheExpirationTime) { + if ((microtime(true) - self::$_calculationCache[$wsTitle][$cellID]['time']) < self::$_calculationCacheExpirationTime) { // echo 'Cache time is still valid
'; $this->_writeDebug('Retrieving value for '.$cellID.' from cache'); // Return the cached result @@ -2228,14 +2302,14 @@ class PHPExcel_Calculation { } } - if ((in_array($wsTitle.'!'.$cellID,$this->debugLogStack)) && ($wsTitle != 'Wrk')) { + if ((in_array($wsTitle.'!'.$cellID,$this->debugLogStack)) && ($wsTitle != "\x00Wrk")) { if ($this->cyclicFormulaCount <= 0) { return $this->_raiseFormulaError('Cyclic Reference in Formula'); } elseif (($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) && ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID)) { return $cellValue; } elseif ($this->_cyclicFormulaCell == $wsTitle.'!'.$cellID) { - $this->_cyclicFormulaCount++; + ++$this->_cyclicFormulaCount; if ($this->_cyclicFormulaCount >= $this->cyclicFormulaCount) { return $cellValue; } @@ -2254,7 +2328,7 @@ class PHPExcel_Calculation { // Save to calculation cache if (!is_null($cellID)) { if (self::$_calculationCacheEnabled) { - self::$_calculationCache[$wsTitle][$cellID]['time'] = (time() + microtime(true)); + self::$_calculationCache[$wsTitle][$cellID]['time'] = microtime(true); self::$_calculationCache[$wsTitle][$cellID]['data'] = $cellValue; } } @@ -2297,11 +2371,12 @@ class PHPExcel_Calculation { if ($resize == 2) { // Given two matrices of (potentially) unequal size, convert the smaller in each dimension to match the larger - self::_resizeMatricesExtend($operand1,$operand2); + self::_resizeMatricesExtend($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns); } elseif ($resize == 1) { // Given two matrices of (potentially) unequal size, convert the larger in each dimension to match the smaller - self::_resizeMatricesShrink($operand1,$operand2); + self::_resizeMatricesShrink($operand1,$operand2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns); } + return array( $matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns); } // function _checkMatrixOperands() @@ -2315,10 +2390,7 @@ class PHPExcel_Calculation { $matrixRows = count($matrix); $matrixColumns = 0; foreach($matrix as $rowKey => $rowValue) { - $colCount = count($rowValue); - if ($colCount > $matrixColumns) { - $matrixColumns = $colCount; - } + $matrixColumns = max(count($rowValue),$matrixColumns); if (!is_array($rowValue)) { $matrix[$rowKey] = array($rowValue); } else { @@ -2336,10 +2408,7 @@ class PHPExcel_Calculation { * @param mixed &$matrix1 First matrix operand * @param mixed &$matrix2 Second matrix operand */ - private static function _resizeMatricesShrink(&$matrix1,&$matrix2) { - list($matrix1Rows,$matrix1Columns) = self::_getMatrixDimensions($matrix1); - list($matrix2Rows,$matrix2Columns) = self::_getMatrixDimensions($matrix2); - + private static function _resizeMatricesShrink(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) { if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) { if ($matrix2Columns < $matrix1Columns) { for ($i = 0; $i < $matrix1Rows; ++$i) { @@ -2378,10 +2447,7 @@ class PHPExcel_Calculation { * @param mixed &$matrix1 First matrix operand * @param mixed &$matrix2 Second matrix operand */ - private static function _resizeMatricesExtend(&$matrix1,&$matrix2) { - list($matrix1Rows,$matrix1Columns) = self::_getMatrixDimensions($matrix1); - list($matrix2Rows,$matrix2Columns) = self::_getMatrixDimensions($matrix2); - + private static function _resizeMatricesExtend(&$matrix1,&$matrix2,$matrix1Rows,$matrix1Columns,$matrix2Rows,$matrix2Columns) { if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) { if ($matrix2Columns < $matrix1Columns) { for ($i = 0; $i < $matrix2Rows; ++$i) { @@ -2424,28 +2490,29 @@ class PHPExcel_Calculation { * @param mixed $value First matrix operand * @return mixed */ - private static function _showValue($value) { - $testArray = PHPExcel_Calculation_Functions::flattenArray($value); - if (count($testArray) == 1) { - $value = array_pop($testArray); - } - - if (is_array($value)) { - $returnMatrix = array(); - $pad = $rpad = ', '; - foreach($value as $row) { - if (is_array($row)) { - $returnMatrix[] = implode($pad,$row); - $rpad = '; '; - } else { - $returnMatrix[] = $row; - } + private function _showValue($value) { + if ($this->writeDebugLog) { + $testArray = PHPExcel_Calculation_Functions::flattenArray($value); + if (count($testArray) == 1) { + $value = array_pop($testArray); } - return '{ '.implode($rpad,$returnMatrix).' }'; - } elseif(is_bool($value)) { - return ($value) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE']; - } + if (is_array($value)) { + $returnMatrix = array(); + $pad = $rpad = ', '; + foreach($value as $row) { + if (is_array($row)) { + $returnMatrix[] = implode($pad,$row); + $rpad = '; '; + } else { + $returnMatrix[] = $row; + } + } + return '{ '.implode($rpad,$returnMatrix).' }'; + } elseif(is_bool($value)) { + return ($value) ? self::$_localeBoolean['TRUE'] : self::$_localeBoolean['FALSE']; + } + } return $value; } // function _showValue() @@ -2456,32 +2523,34 @@ class PHPExcel_Calculation { * @param mixed $value First matrix operand * @return mixed */ - private static function _showTypeDetails($value) { - $testArray = PHPExcel_Calculation_Functions::flattenArray($value); - if (count($testArray) == 1) { - $value = array_pop($testArray); - } - - if (is_null($value)) { - return 'a null value'; - } elseif (is_float($value)) { - $typeString = 'a floating point number'; - } elseif(is_int($value)) { - $typeString = 'an integer number'; - } elseif(is_bool($value)) { - $typeString = 'a boolean'; - } elseif(is_array($value)) { - $typeString = 'a matrix'; - } else { - if ($value == '') { - return 'an empty string'; - } elseif ($value{0} == '#') { - return 'a '.$value.' error'; - } else { - $typeString = 'a string'; + private function _showTypeDetails($value) { + if ($this->writeDebugLog) { + $testArray = PHPExcel_Calculation_Functions::flattenArray($value); + if (count($testArray) == 1) { + $value = array_pop($testArray); } + + if (is_null($value)) { + return 'a null value'; + } elseif (is_float($value)) { + $typeString = 'a floating point number'; + } elseif(is_int($value)) { + $typeString = 'an integer number'; + } elseif(is_bool($value)) { + $typeString = 'a boolean'; + } elseif(is_array($value)) { + $typeString = 'a matrix'; + } else { + if ($value == '') { + return 'an empty string'; + } elseif ($value{0} == '#') { + return 'a '.$value.' error'; + } else { + $typeString = 'a string'; + } + } + return $typeString.' with a value of '.$this->_showValue($value); } - return $typeString.' with a value of '.self::_showValue($value); } // function _showTypeDetails() @@ -2498,9 +2567,10 @@ class PHPExcel_Calculation { $temp = explode('"',$formula); // Open and Closed counts used for trapping mismatched braces in the formula $openCount = $closeCount = 0; - foreach($temp as $i => &$value) { - // Only count/replace in alternate array entries - if (($i % 2) == 0) { + $i = false; + foreach($temp as &$value) { + // Only count/replace in alternating array entries + if ($i = !$i) { $openCount += substr_count($value,'{'); $closeCount += substr_count($value,'}'); $value = str_replace($matrixReplaceFrom,$matrixReplaceTo,$value); @@ -2562,7 +2632,7 @@ class PHPExcel_Calculation { ); // Comparison (Boolean) Operators // These operators work on two values, but always return a boolean result - $comparisonOperators = array('>', '<', '=', '>=', '<=', '<>'); + $comparisonOperators = array('>' => true, '<' => true, '=' => true, '>=' => true, '<=' => true, '<>' => true); // Operator Precedence // This list includes all valid operators, whether binary (including boolean) or unary (such as %) @@ -2597,18 +2667,19 @@ class PHPExcel_Calculation { // should be null in a function call // The guts of the lexical parser // Loop through the formula extracting each operator and operand in turn - while(True) { + while(true) { // echo 'Assessing Expression '.substr($formula, $index).'
'; $opCharacter = $formula{$index}; // Get the first character of the value at the current index position // echo 'Initial character of expression block is '.$opCharacter.'
'; - if ((in_array($opCharacter, $comparisonOperators)) && (strlen($formula) > $index) && (in_array($formula{$index+1}, $comparisonOperators))) { + if ((isset($comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset($comparisonOperators[$formula{$index+1}]))) { $opCharacter .= $formula{++$index}; // echo 'Initial character of expression block is comparison operator '.$opCharacter.'
'; } // Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand $isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match); -// echo '$isOperandOrFunction is '.(($isOperandOrFunction)?'True':'False').'
'; +// echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').'
'; +// var_dump($match); if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus? // echo 'Element is a Negation operator
'; @@ -2618,17 +2689,17 @@ class PHPExcel_Calculation { // echo 'Element is a Percentage operator
'; $stack->push('Unary Operator','%'); // Put a percentage on the stack ++$index; - } elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (rather than plus) can be discarded? + } elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded? // echo 'Element is a Positive number, not Plus operator
'; ++$index; // Drop the redundant plus symbol - } elseif (($opCharacter == '~') && (!$isOperandOrFunction)) { // We have to explicitly deny a tilde, because it's legal - return $this->_raiseFormulaError("Formula Error: Illegal character '~'"); // on the stack but not in the input expression + } elseif ((($opCharacter == '~') || ($opCharacter == '|')) && (!$isOperandOrFunction)) { // We have to explicitly deny a tilde or pipe, because they are legal + return $this->_raiseFormulaError("Formula Error: Illegal character '~'"); // on the stack but not in the input expression - } elseif ((in_array($opCharacter, self::$_operators) or $isOperandOrFunction) && $expectingOperator) { // Are we putting an operator on the stack? + } elseif ((isset(self::$_operators[$opCharacter]) or $isOperandOrFunction) && $expectingOperator) { // Are we putting an operator on the stack? // echo 'Element with value '.$opCharacter.' is an Operator
'; while($stack->count() > 0 && ($o2 = $stack->last()) && - in_array($o2['value'], self::$_operators) && + isset(self::$_operators[$o2['value']]) && @($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) { $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output } @@ -2658,11 +2729,11 @@ class PHPExcel_Calculation { // } $output[] = $d; // Dump the argument count on the output $output[] = $stack->pop(); // Pop the function and push onto the output - if (array_key_exists($functionName, self::$_controlFunctions)) { + if (isset(self::$_controlFunctions[$functionName])) { // echo 'Built-in function '.$functionName.'
'; $expectedArgumentCount = self::$_controlFunctions[$functionName]['argumentCount']; $functionCall = self::$_controlFunctions[$functionName]['functionCall']; - } elseif (array_key_exists($functionName, self::$_PHPExcelFunctions)) { + } elseif (isset(self::$_PHPExcelFunctions[$functionName])) { // echo 'PHPExcel function '.$functionName.'
'; $expectedArgumentCount = self::$_PHPExcelFunctions[$functionName]['argumentCount']; $functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall']; @@ -2670,18 +2741,18 @@ class PHPExcel_Calculation { return $this->_raiseFormulaError("Formula Error: Internal error, non-function on stack"); } // Check the argument count - $argumentCountError = False; + $argumentCountError = false; if (is_numeric($expectedArgumentCount)) { if ($expectedArgumentCount < 0) { // echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount).'
'; if ($argumentCount > abs($expectedArgumentCount)) { - $argumentCountError = True; + $argumentCountError = true; $expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount); } } else { // echo '$expectedArgumentCount is numeric '.$expectedArgumentCount.'
'; if ($argumentCount != $expectedArgumentCount) { - $argumentCountError = True; + $argumentCountError = true; $expectedArgumentCountString = $expectedArgumentCount; } } @@ -2692,19 +2763,19 @@ class PHPExcel_Calculation { switch ($argMatch[2]) { case '+' : if ($argumentCount < $argMatch[1]) { - $argumentCountError = True; + $argumentCountError = true; $expectedArgumentCountString = $argMatch[1].' or more '; } break; case '-' : if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) { - $argumentCountError = True; + $argumentCountError = true; $expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3]; } break; case ',' : if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) { - $argumentCountError = True; + $argumentCountError = true; $expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3]; } break; @@ -2725,7 +2796,7 @@ class PHPExcel_Calculation { // If we've a comma when we're expecting an operand, then what we actually have is a null operand; // so push a null onto the stack if (($expectingOperand) || (!$expectingOperator)) { - $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => NULL); + $output[] = array('type' => 'NULL Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null); } // make sure there was a function $d = $stack->last(2); @@ -2753,7 +2824,7 @@ class PHPExcel_Calculation { if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $val, $matches)) { $val = preg_replace('/\s/','',$val); // echo 'Element '.$val.' is a Function
'; - if (array_key_exists(strtoupper($matches[1]), self::$_PHPExcelFunctions) || array_key_exists(strtoupper($matches[1]), self::$_controlFunctions)) { // it's a func + if (isset(self::$_PHPExcelFunctions[strtoupper($matches[1])]) || isset(self::$_controlFunctions[strtoupper($matches[1])])) { // it's a function $stack->push('Function', strtoupper($val)); $ax = preg_match('/^\s*(\s*\))/i', substr($formula, $index+$length), $amatch); if ($ax) { @@ -2765,12 +2836,12 @@ class PHPExcel_Calculation { } $stack->push('Brace', '('); } else { // it's a var w/ implicit multiplication - $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => NULL); + $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => null); } } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) { // echo 'Element '.$val.' is a Cell reference
'; -// Watch for this case-change when modifying to allow cell references in different worksheets... -// Should only be applied to the actual cell column, not the worksheet name + // Watch for this case-change when modifying to allow cell references in different worksheets... + // Should only be applied to the actual cell column, not the worksheet name // If the last entry on the stack was a : operator, then we have a cell range reference $testPrevOp = $stack->last(1); @@ -2784,11 +2855,12 @@ class PHPExcel_Calculation { if ($startMatches[2] > '') { $val = $startMatches[2].'!'.$val; } + } else { + return $this->_raiseFormulaError("3D Range references are not yet supported"); } } - $cellRef = strtoupper($val); - $output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $cellRef); + $output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $val); // $expectingOperator = false; } else { // it's a variable, constant, string, number or boolean // echo 'Element is a Variable, Constant, String, Number or Boolean
'; @@ -2828,14 +2900,14 @@ class PHPExcel_Calculation { $val = self::_wrapResult(str_replace('""','"',self::_unwrapResult($val))); } elseif (is_numeric($val)) { // echo 'Element is a Number
'; - if ((strpos($val,'.') !== False) || (stripos($val,'e') !== False) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) { + if ((strpos($val,'.') !== false) || (stripos($val,'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) { // echo 'Casting '.$val.' to float
'; $val = (float) $val; } else { // echo 'Casting '.$val.' to integer
'; $val = (integer) $val; } - } elseif (array_key_exists(trim(strtoupper($val)), self::$_ExcelConstants)) { + } elseif (isset(self::$_ExcelConstants[trim(strtoupper($val))])) { $excelConstant = trim(strtoupper($val)); // echo 'Element '.$excelConstant.' is an Excel Constant
'; $val = self::$_ExcelConstants[$excelConstant]; @@ -2843,23 +2915,23 @@ class PHPExcel_Calculation { // echo 'Element '.$localeConstant.' is an Excel Constant
'; $val = self::$_ExcelConstants[$localeConstant]; } - $details = array('type' => 'Value', 'value' => $val, 'reference' => NULL); + $details = array('type' => 'Value', 'value' => $val, 'reference' => null); if ($localeConstant) { $details['localeValue'] = $localeConstant; } $output[] = $details; } $index += $length; } elseif ($opCharacter == '$') { // absolute row or column range - $index++; + ++$index; } elseif ($opCharacter == ')') { // miscellaneous error checking if ($expectingOperand) { - $output[] = array('type' => 'Null Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => NULL); + $output[] = array('type' => 'Null Value', 'value' => self::$_ExcelConstants['NULL'], 'reference' => null); $expectingOperand = false; - $expectingOperator = True; + $expectingOperator = true; } else { return $this->_raiseFormulaError("Formula Error: Unexpected ')'"); } - } elseif (in_array($opCharacter, self::$_operators) && !$expectingOperator) { + } elseif (isset(self::$_operators[$opCharacter]) && !$expectingOperator) { return $this->_raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'"); } else { // I don't even want to know what you did to get here return $this->_raiseFormulaError("Formula Error: An unexpected error occured"); @@ -2868,7 +2940,7 @@ class PHPExcel_Calculation { if ($index == strlen($formula)) { // Did we end with an operator?. // Only valid for the % unary operator - if ((in_array($opCharacter, self::$_operators)) && ($opCharacter != '%')) { + if ((isset(self::$_operators[$opCharacter])) && ($opCharacter != '%')) { return $this->_raiseFormulaError("Formula Error: Operator '$opCharacter' has no operands"); } else { break; @@ -2885,12 +2957,12 @@ class PHPExcel_Calculation { // If we're expecting an operator, but only have a space between the previous and next operands (and both are // Cell References) then we have an INTERSECTION operator // echo 'Possible Intersect Operator
'; - if (($expectingOperator) && (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'.*/i', substr($formula, $index), $match)) && + if (($expectingOperator) && (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'.*/Ui', substr($formula, $index), $match)) && ($output[count($output)-1]['type'] == 'Cell Reference')) { // echo 'Element is an Intersect Operator
'; while($stack->count() > 0 && ($o2 = $stack->last()) && - in_array($o2['value'], self::$_operators) && + isset(self::$_operators[$o2['value']]) && @($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2['value']] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2['value']])) { $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output } @@ -2924,7 +2996,7 @@ class PHPExcel_Calculation { $token = $tokenData['value']; // echo 'Token is '.$token.'
'; // if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack - if (in_array($token, self::$_binaryOperators, true)) { + if (isset(self::$_binaryOperators[$token])) { // echo 'Token is a binary operator
'; // We must have two operands, error if we don't if (is_null($operand2Data = $stack->pop())) return $this->_raiseFormulaError('Internal error - Operand value missing from stack'); @@ -2933,9 +3005,9 @@ class PHPExcel_Calculation { $operand1 = $operand1Data['value']; $operand2 = $operand2Data['value']; if ($token == ':') { - $this->_writeDebug('Evaluating Range '.self::_showValue($operand1Data['reference']).$token.self::_showValue($operand2Data['reference'])); + $this->_writeDebug('Evaluating Range '.$this->_showValue($operand1Data['reference']).$token.$this->_showValue($operand2Data['reference'])); } else { - $this->_writeDebug('Evaluating '.self::_showValue($operand1).' '.$token.' '.self::_showValue($operand2)); + $this->_writeDebug('Evaluating '.$this->_showValue($operand1).' '.$token.' '.$this->_showValue($operand2)); } // Process the operation in the appropriate manner switch ($token) { @@ -2966,7 +3038,7 @@ class PHPExcel_Calculation { if ((trim($operand1Data['value']) != '') && (is_numeric($operand1Data['value']))) { $operand1Data['reference'] = $pCell->getColumn().$operand1Data['value']; } elseif (trim($operand1Data['reference']) == '') { - $operand1Data['reference'] = $pCell->getColumn().$pCell->getRow(); + $operand1Data['reference'] = $pCell->getCoordinate(); } else { $operand1Data['reference'] = $operand1Data['value'].$pCell->getRow(); } @@ -2975,7 +3047,7 @@ class PHPExcel_Calculation { if ((trim($operand2Data['value']) != '') && (is_numeric($operand2Data['value']))) { $operand2Data['reference'] = $pCell->getColumn().$operand2Data['value']; } elseif (trim($operand2Data['reference']) == '') { - $operand2Data['reference'] = $pCell->getColumn().$pCell->getRow(); + $operand2Data['reference'] = $pCell->getCoordinate(); } else { $operand2Data['reference'] = $operand2Data['value'].$pCell->getRow(); } @@ -2996,7 +3068,7 @@ class PHPExcel_Calculation { } $stack->push('Cell Reference',$cellValue,$cellRef); } else { - $stack->push('Error',PHPExcel_Calculation_Functions::REF(),NULL); + $stack->push('Error',PHPExcel_Calculation_Functions::REF(),null); } break; @@ -3030,7 +3102,7 @@ class PHPExcel_Calculation { self::_checkMatrixOperands($operand1,$operand2,2); try { // Convert operand 1 from a PHP array to a matrix - $matrix = new Matrix($operand1); + $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1); // Perform the required operation against the operand 1 matrix, passing in operand 2 $matrixResult = $matrix->concat($operand2); $result = $matrixResult->getArray(); @@ -3041,21 +3113,21 @@ class PHPExcel_Calculation { } else { $result = '"'.str_replace('""','"',self::_unwrapResult($operand1,'"').self::_unwrapResult($operand2,'"')).'"'; } - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); $stack->push('Value',$result); break; case '|' : // Intersect $rowIntersect = array_intersect_key($operand1,$operand2); $cellIntersect = $oCol = $oRow = array(); - foreach(array_keys($rowIntersect) as $col) { - $oCol[] = PHPExcel_Cell::columnIndexFromString($col) - 1; - $cellIntersect[$col] = array_intersect_key($operand1[$col],$operand2[$col]); - foreach($cellIntersect[$col] as $row => $data) { - $oRow[] = $row; + foreach(array_keys($rowIntersect) as $row) { + $oRow[] = $row; + foreach($rowIntersect[$row] as $col => $data) { + $oCol[] = PHPExcel_Cell::columnIndexFromString($col) - 1; + $cellIntersect[$row] = array_intersect_key($operand1[$row],$operand2[$row]); } } $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow); - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails($cellIntersect)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($cellIntersect)); $stack->push('Value',$cellIntersect,$cellRef); break; } @@ -3067,24 +3139,24 @@ class PHPExcel_Calculation { $arg = $arg['value']; if ($token === '~') { // echo 'Token is a negation operator
'; - $this->_writeDebug('Evaluating Negation of '.self::_showValue($arg)); + $this->_writeDebug('Evaluating Negation of '.$this->_showValue($arg)); $multiplier = -1; } else { // echo 'Token is a percentile operator
'; - $this->_writeDebug('Evaluating Percentile of '.self::_showValue($arg)); + $this->_writeDebug('Evaluating Percentile of '.$this->_showValue($arg)); $multiplier = 0.01; } if (is_array($arg)) { self::_checkMatrixOperands($arg,$multiplier,2); try { - $matrix1 = new Matrix($arg); + $matrix1 = new PHPExcel_Shared_JAMA_Matrix($arg); $matrixResult = $matrix1->arrayTimesEquals($multiplier); $result = $matrixResult->getArray(); } catch (Exception $ex) { $this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage()); $result = '#VALUE!'; } - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); $stack->push('Value',$result); } else { $this->_executeNumericBinaryOperation($cellID,$multiplier,$arg,'*','arrayTimesEquals',$stack); @@ -3109,7 +3181,7 @@ class PHPExcel_Calculation { } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cells '.$cellRef.' in worksheet '.$matches[2].' is '.self::_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cells '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue)); // $cellRef = $matches[2].'!'.$cellRef; } else { // echo '$cellRef='.$cellRef.' in current worksheet
'; @@ -3119,7 +3191,7 @@ class PHPExcel_Calculation { } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cells '.$cellRef.' is '.self::_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cells '.$cellRef.' is '.$this->_showTypeDetails($cellValue)); } } } else { @@ -3138,12 +3210,12 @@ class PHPExcel_Calculation { $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false); $pCell->attach($pCellParent); } else { - $cellValue = PHPExcel_Calculation_Functions::REF(); + $cellValue = null; } } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cell '.$cellRef.' in worksheet '.$matches[2].' is '.self::_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cell '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue)); // $cellRef = $matches[2].'!'.$cellRef; } else { // echo '$cellRef='.$cellRef.' in current worksheet
'; @@ -3152,9 +3224,9 @@ class PHPExcel_Calculation { $cellValue = $this->extractCellRange($cellRef, $pCellParent, false); $pCell->attach($pCellParent); } else { - $cellValue = NULL; + $cellValue = null; } - $this->_writeDebug('Evaluation Result for cell '.$cellRef.' is '.self::_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cell '.$cellRef.' is '.$this->_showTypeDetails($cellValue)); } } } @@ -3169,12 +3241,12 @@ class PHPExcel_Calculation { if ($functionName != 'MKMATRIX') { $this->_writeDebug('Evaluating Function '.self::_localeFunc($functionName).'() with '.(($argCount == 0) ? 'no' : $argCount).' argument'.(($argCount == 1) ? '' : 's')); } - if ((array_key_exists($functionName, self::$_PHPExcelFunctions)) || (array_key_exists($functionName, self::$_controlFunctions))) { // function - if (array_key_exists($functionName, self::$_PHPExcelFunctions)) { + if ((isset(self::$_PHPExcelFunctions[$functionName])) || (isset(self::$_controlFunctions[$functionName]))) { // function + if (isset(self::$_PHPExcelFunctions[$functionName])) { $functionCall = self::$_PHPExcelFunctions[$functionName]['functionCall']; $passByReference = isset(self::$_PHPExcelFunctions[$functionName]['passByReference']); $passCellReference = isset(self::$_PHPExcelFunctions[$functionName]['passCellReference']); - } elseif (array_key_exists($functionName, self::$_controlFunctions)) { + } elseif (isset(self::$_controlFunctions[$functionName])) { $functionCall = self::$_controlFunctions[$functionName]['functionCall']; $passByReference = isset(self::$_controlFunctions[$functionName]['passByReference']); $passCellReference = isset(self::$_controlFunctions[$functionName]['passCellReference']); @@ -3190,48 +3262,50 @@ class PHPExcel_Calculation { (self::$_PHPExcelFunctions[$functionName]['passByReference'][$a])) { if (is_null($arg['reference'])) { $args[] = $cellID; - if ($functionName != 'MKMATRIX') { $argArrayVals[] = self::_showValue($cellID); } + if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($cellID); } } else { $args[] = $arg['reference']; - if ($functionName != 'MKMATRIX') { $argArrayVals[] = self::_showValue($arg['reference']); } + if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['reference']); } } } else { $args[] = self::_unwrapResult($arg['value']); - if ($functionName != 'MKMATRIX') { $argArrayVals[] = self::_showValue($arg['value']); } + if ($functionName != 'MKMATRIX') { $argArrayVals[] = $this->_showValue($arg['value']); } } } // Reverse the order of the arguments krsort($args); if (($passByReference) && ($argCount == 0)) { $args[] = $cellID; - $argArrayVals[] = self::_showValue($cellID); + $argArrayVals[] = $this->_showValue($cellID); } // echo 'Arguments are: '; // print_r($args); // echo '
'; if ($functionName != 'MKMATRIX') { - krsort($argArrayVals); - $this->_writeDebug('Evaluating '. self::_localeFunc($functionName).'( '.implode(self::$_localeArgumentSeparator.' ',$argArrayVals).' )'); + if ($this->writeDebugLog) { + krsort($argArrayVals); + $this->_writeDebug('Evaluating '. self::_localeFunc($functionName).'( '.implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)).' )'); + } } // Process each argument in turn, building the return value as an array // if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) { // $operand1 = $args[1]; -// $this->_writeDebug('Argument is a matrix: '.self::_showValue($operand1)); +// $this->_writeDebug('Argument is a matrix: '.$this->_showValue($operand1)); // $result = array(); // $row = 0; // foreach($operand1 as $args) { // if (is_array($args)) { // foreach($args as $arg) { -// $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.self::_showValue($arg).' )'); +// $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($arg).' )'); // $r = call_user_func_array($functionCall,$arg); -// $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.self::_showTypeDetails($r)); +// $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r)); // $result[$row][] = $r; // } // ++$row; // } else { -// $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.self::_showValue($args).' )'); +// $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($args).' )'); // $r = call_user_func_array($functionCall,$args); -// $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.self::_showTypeDetails($r)); +// $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r)); // $result[] = $r; // } // } @@ -3251,19 +3325,19 @@ class PHPExcel_Calculation { } // } if ($functionName != 'MKMATRIX') { - $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.self::_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($result)); } $stack->push('Value',self::_wrapResult($result)); } } else { // if the token is a number, boolean, string or an Excel error, push it onto the stack - if (array_key_exists(strtoupper($token), self::$_ExcelConstants)) { + if (isset(self::$_ExcelConstants[strtoupper($token)])) { $excelConstant = strtoupper($token); // echo 'Token is a PHPExcel constant: '.$excelConstant.'
'; $stack->push('Constant Value',self::$_ExcelConstants[$excelConstant]); - $this->_writeDebug('Evaluating Constant '.$excelConstant.' as '.self::_showTypeDetails(self::$_ExcelConstants[$excelConstant])); - } elseif ((is_numeric($token)) || (is_bool($token)) || (is_null($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) { + $this->_writeDebug('Evaluating Constant '.$excelConstant.' as '.$this->_showTypeDetails(self::$_ExcelConstants[$excelConstant])); + } elseif ((is_numeric($token)) || (is_null($token)) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) { // echo 'Token is a number, boolean, string, null or an Excel error
'; $stack->push('Value',$token); // if the token is a named range, push the named range name onto the stack @@ -3274,7 +3348,7 @@ class PHPExcel_Calculation { $this->_writeDebug('Evaluating Named Range '.$namedRange); $cellValue = $this->extractNamedRange($namedRange, ((null !== $pCell) ? $pCellParent : null), false); $pCell->attach($pCellParent); - $this->_writeDebug('Evaluation Result for named range '.$namedRange.' is '.self::_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for named range '.$namedRange.' is '.$this->_showTypeDetails($cellValue)); $stack->push('Named Range',$cellValue,$namedRange); } else { return $this->_raiseFormulaError("undefined variable '$token'"); @@ -3304,12 +3378,12 @@ class PHPExcel_Calculation { // If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations if ($operand > '' && $operand{0} == '#') { $stack->push('Value', $operand); - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails($operand)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($operand)); return false; } elseif (!PHPExcel_Shared_String::convertToNumberIfFraction($operand)) { // If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations $stack->push('Value', '#VALUE!'); - $this->_writeDebug('Evaluation Result is a '.self::_showTypeDetails('#VALUE!')); + $this->_writeDebug('Evaluation Result is a '.$this->_showTypeDetails('#VALUE!')); return false; } } @@ -3326,14 +3400,14 @@ class PHPExcel_Calculation { $result = array(); if ((is_array($operand1)) && (!is_array($operand2))) { foreach($operand1 as $x => $operandData) { - $this->_writeDebug('Evaluating '.self::_showValue($operandData).' '.$operation.' '.self::_showValue($operand2)); + $this->_writeDebug('Evaluating '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2)); $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2,$operation,$stack); $r = $stack->pop(); $result[$x] = $r['value']; } } elseif ((!is_array($operand1)) && (is_array($operand2))) { foreach($operand2 as $x => $operandData) { - $this->_writeDebug('Evaluating '.self::_showValue($operand1).' '.$operation.' '.self::_showValue($operandData)); + $this->_writeDebug('Evaluating '.$this->_showValue($operand1).' '.$operation.' '.$this->_showValue($operandData)); $this->_executeBinaryComparisonOperation($cellID,$operand1,$operandData,$operation,$stack); $r = $stack->pop(); $result[$x] = $r['value']; @@ -3341,14 +3415,14 @@ class PHPExcel_Calculation { } else { if (!$recursingArrays) { self::_checkMatrixOperands($operand1,$operand2,2); } foreach($operand1 as $x => $operandData) { - $this->_writeDebug('Evaluating '.self::_showValue($operandData).' '.$operation.' '.self::_showValue($operand2[$x])); - $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,True); + $this->_writeDebug('Evaluating '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2[$x])); + $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,true); $r = $stack->pop(); $result[$x] = $r['value']; } } // Log the result details - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Array',$result); return true; @@ -3387,7 +3461,7 @@ class PHPExcel_Calculation { } // Log the result details - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Value',$result); return true; @@ -3399,15 +3473,28 @@ class PHPExcel_Calculation { if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return false; if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return false; + $executeMatrixOperation = false; // If either of the operands is a matrix, we need to treat them both as matrices // (converting the other operand to a matrix if need be); then perform the required // matrix operation if ((is_array($operand1)) || (is_array($operand2))) { // Ensure that both operands are arrays/matrices - self::_checkMatrixOperands($operand1,$operand2,2); + $executeMatrixOperation = true; + $mSize = array(); + list($mSize[],$mSize[],$mSize[],$mSize[]) = self::_checkMatrixOperands($operand1,$operand2,2); + + // But if they're both single cell matrices, then we can treat them as simple values + if (array_sum($mSize) == 4) { + $executeMatrixOperation = false; + $operand1 = $operand1[0][0]; + $operand2 = $operand2[0][0]; + } + } + + if ($executeMatrixOperation) { try { // Convert operand 1 from a PHP array to a matrix - $matrix = new Matrix($operand1); + $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1); // Perform the required operation against the operand 1 matrix, passing in operand 2 $matrixResult = $matrix->$matrixFunction($operand2); $result = $matrixResult->getArray(); @@ -3416,40 +3503,45 @@ class PHPExcel_Calculation { $result = '#VALUE!'; } } else { - // If we're dealing with non-matrix operations, execute the necessary operation - switch ($operation) { - // Addition - case '+': - $result = $operand1+$operand2; - break; - // Subtraction - case '-': - $result = $operand1-$operand2; - break; - // Multiplication - case '*': - $result = $operand1*$operand2; - break; - // Division - case '/': - if ($operand2 == 0) { - // Trap for Divide by Zero error - $stack->push('Value','#DIV/0!'); - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails('#DIV/0!')); - return false; - } else { - $result = $operand1/$operand2; - } - break; - // Power - case '^': - $result = pow($operand1,$operand2); - break; + if ((PHPExcel_Calculation_Functions::getCompatibilityMode() != PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) && + ((is_string($operand1) && !is_numeric($operand1)) || (is_string($operand2) && !is_numeric($operand2)))) { + $result = PHPExcel_Calculation_Functions::VALUE(); + } else { + // If we're dealing with non-matrix operations, execute the necessary operation + switch ($operation) { + // Addition + case '+': + $result = $operand1+$operand2; + break; + // Subtraction + case '-': + $result = $operand1-$operand2; + break; + // Multiplication + case '*': + $result = $operand1*$operand2; + break; + // Division + case '/': + if ($operand2 == 0) { + // Trap for Divide by Zero error + $stack->push('Value','#DIV/0!'); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails('#DIV/0!')); + return false; + } else { + $result = $operand1/$operand2; + } + break; + // Power + case '^': + $result = pow($operand1,$operand2); + break; + } } } // Log the result details - $this->_writeDebug('Evaluation Result is '.self::_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Value',$result); return true; @@ -3459,6 +3551,9 @@ class PHPExcel_Calculation { private function _writeDebug($message) { // Only write the debug log if logging is enabled if ($this->writeDebugLog) { + if ($this->echoDebugLog) { + echo implode(' -> ',$this->debugLogStack).' -> '.$message,'
'; + } $this->debugLog[] = implode(' -> ',$this->debugLogStack).' -> '.$message; } } // function _writeDebug() @@ -3500,23 +3595,24 @@ class PHPExcel_Calculation { // Extract range $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange); $pRange = $pSheet->getTitle().'!'.$pRange; - if (count($aReferences) == 1) { - list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($aReferences[0]); + if (!isset($aReferences[1])) { + // Single cell in range + list($currentCol,$currentRow) = sscanf($aReferences[0],'%[A-Z]%d'); if ($pSheet->cellExists($aReferences[0])) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = NULL; + $returnValue[$currentRow][$currentCol] = null; } } else { - // Extract cell data + // Extract cell data for all cells in the range foreach ($aReferences as $reference) { // Extract range - list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference); + list($currentCol,$currentRow) = sscanf($reference,'%[A-Z]%d'); if ($pSheet->cellExists($reference)) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = NULL; + $returnValue[$currentRow][$currentCol] = null; } } } @@ -3556,9 +3652,17 @@ class PHPExcel_Calculation { $namedRange = PHPExcel_NamedRange::resolveRange($pRange, $pSheet); if (!is_null($namedRange)) { $pSheet = $namedRange->getWorksheet(); -//// echo 'Named Range '.$pRange.' ('; +// echo 'Named Range '.$pRange.' ('; $pRange = $namedRange->getRange(); -//// echo $pRange.') is in sheet '.$namedRange->getWorksheet()->getTitle().'
'; + $splitRange = PHPExcel_Cell::splitRange($pRange); + // Convert row and column references + if (ctype_alpha($splitRange[0][0])) { + $pRange = $splitRange[0][0] . '1:' . $splitRange[0][1] . $namedRange->getWorksheet()->getHighestRow(); + } elseif(ctype_digit($splitRange[0][0])) { + $pRange = 'A' . $splitRange[0][0] . ':' . $namedRange->getWorksheet()->getHighestColumn() . $splitRange[0][1]; + } +// echo $pRange.') is in sheet '.$namedRange->getWorksheet()->getTitle().'
'; + // if ($pSheet->getTitle() != $namedRange->getWorksheet()->getTitle()) { // if (!$namedRange->getLocalOnly()) { // $pSheet = $namedRange->getWorksheet(); @@ -3572,15 +3676,17 @@ class PHPExcel_Calculation { // Extract range $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange); - if (count($aReferences) == 1) { +// var_dump($aReferences); + if (!isset($aReferences[1])) { + // Single cell (or single column or row) in range list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($aReferences[0]); if ($pSheet->cellExists($aReferences[0])) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = NULL; + $returnValue[$currentRow][$currentCol] = null; } } else { - // Extract cell data + // Extract cell data for all cells in the range foreach ($aReferences as $reference) { // Extract range list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference); @@ -3588,7 +3694,7 @@ class PHPExcel_Calculation { if ($pSheet->cellExists($reference)) { $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog); } else { - $returnValue[$currentRow][$currentCol] = NULL; + $returnValue[$currentRow][$currentCol] = null; } } } @@ -3640,13 +3746,32 @@ class PHPExcel_Calculation { } // function listFunctions() + /** + * Get a list of all Excel function names + * + * @return array + */ + public function listAllFunctionNames() { + return array_keys(self::$_PHPExcelFunctions); + } // function listAllFunctionNames() + /** * Get a list of implemented Excel function names * * @return array */ public function listFunctionNames() { - return array_keys(self::$_PHPExcelFunctions); + // Return value + $returnValue = array(); + // Loop functions + foreach(self::$_PHPExcelFunctions as $functionName => $function) { + if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') { + $returnValue[] = $functionName; + } + } + + // Return + return $returnValue; } // function listFunctionNames() } // class PHPExcel_Calculation diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Database.php b/libraries/PHPExcel/PHPExcel/Calculation/Database.php new file mode 100644 index 000000000..8696d225b --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/Database.php @@ -0,0 +1,384 @@ + $criteriaName) { + $testCondition = array(); + $testConditionCount = 0; + foreach($criteria as $row => $criterion) { + if ($criterion[$key] > '') { + $testCondition[] = '[:'.$criteriaName.']'.PHPExcel_Calculation_Functions::_ifCondition($criterion[$key]); + $testConditionCount++; + } + } + if ($testConditionCount > 1) { + $testConditions[] = 'OR('.implode(',',$testCondition).')'; + $testConditionsCount++; + } elseif($testConditionCount == 1) { + $testConditions[] = $testCondition[0]; + $testConditionsCount++; + } + } + if ($testConditionsCount > 1) { + $testConditionSet = 'AND('.implode(',',$testConditions).')'; + } elseif($testConditionsCount == 1) { + $testConditionSet = $testConditions[0]; + } + + // Loop through each row of the database + foreach($database as $dataRow => $dataValues) { + // Substitute actual values from the database row for our [:placeholders] + $testConditionList = $testConditionSet; + foreach($criteriaNames as $key => $criteriaName) { + $k = array_search($criteriaName,$fieldNames); + if (isset($dataValues[$k])) { + $dataValue = $dataValues[$k]; + $dataValue = (is_string($dataValue)) ? PHPExcel_Calculation::_wrapResult(strtoupper($dataValue)) : $dataValue; + $testConditionList = str_replace('[:'.$criteriaName.']',$dataValue,$testConditionList); + } + } + // evaluate the criteria against the row data + $result = PHPExcel_Calculation::getInstance()->_calculateFormulaValue('='.$testConditionList); + // If the row failed to meet the criteria, remove it from the database + if (!$result) { + unset($database[$dataRow]); + } + } + + return $database; + } + + + /** + * DAVERAGE + * + */ + public static function DAVERAGE($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::AVERAGE($colData); + } // function DAVERAGE() + + /** + * DCOUNT + * + */ + public static function DCOUNT($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::COUNT($colData); + } // function DCOUNT() + + /** + * DCOUNTA + * + */ + public static function DCOUNTA($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::COUNTA($colData); + } // function DCOUNTA() + + /** + * DGET + * + */ + public static function DGET($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + if (count($colData) > 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + + return $colData[0]; + } // function DGET() + + /** + * DMAX + * + */ + public static function DMAX($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::MAX($colData); + } // function DMAX() + + /** + * DMIN + * + */ + public static function DMIN($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::MIN($colData); + } // function DMIN() + + /** + * DPRODUCT + * + */ + public static function DPRODUCT($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_MathTrig::PRODUCT($colData); + } // function DPRODUCT() + + /** + * DSTDEV + * + */ + public static function DSTDEV($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::STDEV($colData); + } // function DSTDEV() + + /** + * DSTDEVP + * + */ + public static function DSTDEVP($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::STDEVP($colData); + } // function DSTDEVP() + + /** + * DSUM + * + */ + public static function DSUM($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_MathTrig::SUM($colData); + } // function DSUM() + + /** + * DVAR + * + */ + public static function DVAR($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::VARFunc($colData); + } // function DVAR() + + /** + * DVARP + * + */ + public static function DVARP($database,$field,$criteria) { + $field = self::__fieldExtract($database,$field); + if (is_null($field)) { + return NULL; + } + + // reduce the database to a set of rows that match all the criteria + $database = self::__filter($database,$criteria); + // extract an array of values for the requested column + $colData = array(); + foreach($database as $row) { + $colData[] = $row[$field]; + } + + // Return + return PHPExcel_Calculation_Statistical::VARP($colData); + } // function DVARP() + + +} // class PHPExcel_Calculation_Database diff --git a/libraries/PHPExcel/PHPExcel/Calculation/DateTime.php b/libraries/PHPExcel/PHPExcel/Calculation/DateTime.php new file mode 100644 index 000000000..e32de01eb --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/DateTime.php @@ -0,0 +1,1178 @@ +format('m'); + $oYear = (int) $PHPDateObject->format('Y'); + + $adjustmentMonthsString = (string) $adjustmentMonths; + if ($adjustmentMonths > 0) { + $adjustmentMonthsString = '+'.$adjustmentMonths; + } + if ($adjustmentMonths != 0) { + $PHPDateObject->modify($adjustmentMonthsString.' months'); + } + $nMonth = (int) $PHPDateObject->format('m'); + $nYear = (int) $PHPDateObject->format('Y'); + + $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12); + if ($monthDiff != $adjustmentMonths) { + $adjustDays = (int) $PHPDateObject->format('d'); + $adjustDaysString = '-'.$adjustDays.' days'; + $PHPDateObject->modify($adjustDaysString); + } + return $PHPDateObject; + } // function _adjustDateByMonths() + + + /** + * DATETIMENOW + * + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function DATETIMENOW() { + $saveTimeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + $retValue = False; + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time()); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + $retValue = (integer) time(); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + $retValue = new DateTime(); + break; + } + date_default_timezone_set($saveTimeZone); + + return $retValue; + } // function DATETIMENOW() + + + /** + * DATENOW + * + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function DATENOW() { + $saveTimeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + $retValue = False; + $excelDateTime = floor(PHPExcel_Shared_Date::PHPToExcel(time())); + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + $retValue = (float) $excelDateTime; + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime) - 3600; + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + $retValue = PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime); + break; + } + date_default_timezone_set($saveTimeZone); + + return $retValue; + } // function DATENOW() + + + /** + * DATE + * + * @param long $year + * @param long $month + * @param long $day + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function DATE($year = 0, $month = 1, $day = 1) { + $year = (integer) PHPExcel_Calculation_Functions::flattenSingleValue($year); + $month = (integer) PHPExcel_Calculation_Functions::flattenSingleValue($month); + $day = (integer) PHPExcel_Calculation_Functions::flattenSingleValue($day); + + $baseYear = PHPExcel_Shared_Date::getExcelCalendar(); + // Validate parameters + if ($year < ($baseYear-1900)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ((($baseYear-1900) != 0) && ($year < $baseYear) && ($year >= 1900)) { + return PHPExcel_Calculation_Functions::NaN(); + } + + if (($year < $baseYear) && ($year >= ($baseYear-1900))) { + $year += 1900; + } + + if ($month < 1) { + // Handle year/month adjustment if month < 1 + --$month; + $year += ceil($month / 12) - 1; + $month = 13 - abs($month % 12); + } elseif ($month > 12) { + // Handle year/month adjustment if month > 12 + $year += floor($month / 12); + $month = ($month % 12); + } + + // Re-validate the year parameter after adjustments + if (($year < $baseYear) || ($year >= 10000)) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day); + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + return (float) $excelDateValue; + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue); + break; + } + } // function DATE() + + + /** + * TIME + * + * @param long $hour + * @param long $minute + * @param long $second + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function TIME($hour = 0, $minute = 0, $second = 0) { + $hour = PHPExcel_Calculation_Functions::flattenSingleValue($hour); + $minute = PHPExcel_Calculation_Functions::flattenSingleValue($minute); + $second = PHPExcel_Calculation_Functions::flattenSingleValue($second); + + if ($hour == '') { $hour = 0; } + if ($minute == '') { $minute = 0; } + if ($second == '') { $second = 0; } + + if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $hour = (integer) $hour; + $minute = (integer) $minute; + $second = (integer) $second; + + if ($second < 0) { + $minute += floor($second / 60); + $second = 60 - abs($second % 60); + if ($second == 60) { $second = 0; } + } elseif ($second >= 60) { + $minute += floor($second / 60); + $second = $second % 60; + } + if ($minute < 0) { + $hour += floor($minute / 60); + $minute = 60 - abs($minute % 60); + if ($minute == 60) { $minute = 0; } + } elseif ($minute >= 60) { + $hour += floor($minute / 60); + $minute = $minute % 60; + } + + if ($hour > 23) { + $hour = $hour % 24; + } elseif ($hour < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + $date = 0; + $calendar = PHPExcel_Shared_Date::getExcelCalendar(); + if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900) { + $date = 1; + } + return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(1970, 1, 1, $hour-1, $minute, $second)); // -2147468400; // -2147472000 + 3600 + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + $dayAdjust = 0; + if ($hour < 0) { + $dayAdjust = floor($hour / 24); + $hour = 24 - abs($hour % 24); + if ($hour == 24) { $hour = 0; } + } elseif ($hour >= 24) { + $dayAdjust = floor($hour / 24); + $hour = $hour % 24; + } + $phpDateObject = new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second); + if ($dayAdjust != 0) { + $phpDateObject->modify($dayAdjust.' days'); + } + return $phpDateObject; + break; + } + } // function TIME() + + + /** + * DATEVALUE + * + * @param string $dateValue + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function DATEVALUE($dateValue = 1) { + $dateValue = trim(PHPExcel_Calculation_Functions::flattenSingleValue($dateValue),'"'); + // Strip any ordinals because they're allowed in Excel (English only) + $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui','$1$3',$dateValue); + // Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany) + $dateValue = str_replace(array('/','.','-',' '),array(' ',' ',' ',' '),$dateValue); + + $yearFound = false; + $t1 = explode(' ',$dateValue); + foreach($t1 as &$t) { + if ((is_numeric($t)) && ($t > 31)) { + if ($yearFound) { + return PHPExcel_Calculation_Functions::VALUE(); + } else { + if ($t < 100) { $t += 1900; } + $yearFound = true; + } + } + } + if ((count($t1) == 1) && (strpos($t,':') != false)) { + // We've been fed a time value without any date + return 0.0; + } elseif (count($t1) == 2) { + // We only have two parts of the date: either day/month or month/year + if ($yearFound) { + array_unshift($t1,1); + } else { + array_push($t1,date('Y')); + } + } + unset($t); + $dateValue = implode(' ',$t1); + + $PHPDateArray = date_parse($dateValue); + if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) { + $testVal1 = strtok($dateValue,'- '); + if ($testVal1 !== False) { + $testVal2 = strtok('- '); + if ($testVal2 !== False) { + $testVal3 = strtok('- '); + if ($testVal3 === False) { + $testVal3 = strftime('%Y'); + } + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + $PHPDateArray = date_parse($testVal1.'-'.$testVal2.'-'.$testVal3); + if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) { + $PHPDateArray = date_parse($testVal2.'-'.$testVal1.'-'.$testVal3); + if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + } + + if (($PHPDateArray !== False) && ($PHPDateArray['error_count'] == 0)) { + // Execute function + if ($PHPDateArray['year'] == '') { $PHPDateArray['year'] = strftime('%Y'); } + if ($PHPDateArray['month'] == '') { $PHPDateArray['month'] = strftime('%m'); } + if ($PHPDateArray['day'] == '') { $PHPDateArray['day'] = strftime('%d'); } + $excelDateValue = floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second'])); + + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + return (float) $excelDateValue; + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00'); + break; + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function DATEVALUE() + + + /** + * TIMEVALUE + * + * @param string $timeValue + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function TIMEVALUE($timeValue) { + $timeValue = trim(PHPExcel_Calculation_Functions::flattenSingleValue($timeValue),'"'); + $timeValue = str_replace(array('/','.'),array('-','-'),$timeValue); + + $PHPDateArray = date_parse($timeValue); + if (($PHPDateArray !== False) && ($PHPDateArray['error_count'] == 0)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']); + } else { + $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel(1900,1,1,$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']) - 1; + } + + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + return (float) $excelDateValue; + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + return (integer) $phpDateValue = PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+25569) - 3600;; + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']); + break; + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function TIMEVALUE() + + + /** + * DATEDIF + * + * @param long $startDate Excel date serial value or a standard date string + * @param long $endDate Excel date serial value or a standard date string + * @param string $unit + * @return long Interval between the dates + */ + public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D') { + $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate); + $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate); + $unit = strtoupper(PHPExcel_Calculation_Functions::flattenSingleValue($unit)); + + if (is_string($startDate = self::_getDateValue($startDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($endDate = self::_getDateValue($endDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Validate parameters + if ($startDate >= $endDate) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + $difference = $endDate - $startDate; + + $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate); + $startDays = $PHPStartDateObject->format('j'); + $startMonths = $PHPStartDateObject->format('n'); + $startYears = $PHPStartDateObject->format('Y'); + + $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate); + $endDays = $PHPEndDateObject->format('j'); + $endMonths = $PHPEndDateObject->format('n'); + $endYears = $PHPEndDateObject->format('Y'); + + $retVal = PHPExcel_Calculation_Functions::NaN(); + switch ($unit) { + case 'D': + $retVal = intval($difference); + break; + case 'M': + $retVal = intval($endMonths - $startMonths) + (intval($endYears - $startYears) * 12); + // We're only interested in full months + if ($endDays < $startDays) { + --$retVal; + } + break; + case 'Y': + $retVal = intval($endYears - $startYears); + // We're only interested in full months + if ($endMonths < $startMonths) { + --$retVal; + } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) { + --$retVal; + } + break; + case 'MD': + if ($endDays < $startDays) { + $retVal = $endDays; + $PHPEndDateObject->modify('-'.$endDays.' days'); + $adjustDays = $PHPEndDateObject->format('j'); + if ($adjustDays > $startDays) { + $retVal += ($adjustDays - $startDays); + } + } else { + $retVal = $endDays - $startDays; + } + break; + case 'YM': + $retVal = intval($endMonths - $startMonths); + if ($retVal < 0) $retVal = 12 + $retVal; + // We're only interested in full months + if ($endDays < $startDays) { + --$retVal; + } + break; + case 'YD': + $retVal = intval($difference); + if ($endYears > $startYears) { + while ($endYears > $startYears) { + $PHPEndDateObject->modify('-1 year'); + $endYears = $PHPEndDateObject->format('Y'); + } + $retVal = $PHPEndDateObject->format('z') - $PHPStartDateObject->format('z'); + if ($retVal < 0) { $retVal += 365; } + } + break; + } + return $retVal; + } // function DATEDIF() + + + /** + * DAYS360 + * + * @param long $startDate Excel date serial value or a standard date string + * @param long $endDate Excel date serial value or a standard date string + * @param boolean $method US or European Method + * @return long PHP date/time serial + */ + public static function DAYS360($startDate = 0, $endDate = 0, $method = false) { + $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate); + $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate); + + if (is_string($startDate = self::_getDateValue($startDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($endDate = self::_getDateValue($endDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Execute function + $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate); + $startDay = $PHPStartDateObject->format('j'); + $startMonth = $PHPStartDateObject->format('n'); + $startYear = $PHPStartDateObject->format('Y'); + + $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate); + $endDay = $PHPEndDateObject->format('j'); + $endMonth = $PHPEndDateObject->format('n'); + $endYear = $PHPEndDateObject->format('Y'); + + return self::_dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method); + } // function DAYS360() + + + /** + * YEARFRAC + * + * Calculates the fraction of the year represented by the number of whole days between two dates (the start_date and the + * end_date). Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or obligations + * to assign to a specific term. + * + * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string + * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string + * @param integer $method Method used for the calculation + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float fraction of the year + */ + public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0) { + $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate); + $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate); + $method = PHPExcel_Calculation_Functions::flattenSingleValue($method); + + if (is_string($startDate = self::_getDateValue($startDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($endDate = self::_getDateValue($endDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) { + switch($method) { + case 0 : + return self::DAYS360($startDate,$endDate) / 360; + break; + case 1 : + $days = self::DATEDIF($startDate,$endDate); + $startYear = self::YEAR($startDate); + $endYear = self::YEAR($endDate); + $years = $endYear - $startYear + 1; + $leapDays = 0; + if ($years == 1) { + if (self::_isLeapYear($endYear)) { + $startMonth = self::MONTHOFYEAR($startDate); + $endMonth = self::MONTHOFYEAR($endDate); + $endDay = self::DAYOFMONTH($endDate); + if (($startMonth < 3) || + (($endMonth * 100 + $endDay) >= (2 * 100 + 29))) { + $leapDays += 1; + } + } + } else { + for($year = $startYear; $year <= $endYear; ++$year) { + if ($year == $startYear) { + $startMonth = self::MONTHOFYEAR($startDate); + $startDay = self::DAYOFMONTH($startDate); + if ($startMonth < 3) { + $leapDays += (self::_isLeapYear($year)) ? 1 : 0; + } + } elseif($year == $endYear) { + $endMonth = self::MONTHOFYEAR($endDate); + $endDay = self::DAYOFMONTH($endDate); + if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) { + $leapDays += (self::_isLeapYear($year)) ? 1 : 0; + } + } else { + $leapDays += (self::_isLeapYear($year)) ? 1 : 0; + } + } + if ($years == 2) { + if (($leapDays == 0) && (self::_isLeapYear($startYear)) && ($days > 365)) { + $leapDays = 1; + } elseif ($days < 366) { + $years = 1; + } + } + $leapDays /= $years; + } + return $days / (365 + $leapDays); + break; + case 2 : + return self::DATEDIF($startDate,$endDate) / 360; + break; + case 3 : + return self::DATEDIF($startDate,$endDate) / 365; + break; + case 4 : + return self::DAYS360($startDate,$endDate,True) / 360; + break; + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function YEARFRAC() + + + /** + * NETWORKDAYS + * + * @param mixed Start date + * @param mixed End date + * @param array of mixed Optional Date Series + * @return long Interval between the dates + */ + public static function NETWORKDAYS($startDate,$endDate) { + // Retrieve the mandatory start and end date that are referenced in the function definition + $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate); + $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate); + // Flush the mandatory start and end date that are referenced in the function definition, and get the optional days + $dateArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + array_shift($dateArgs); + array_shift($dateArgs); + + // Validate the start and end dates + if (is_string($startDate = $sDate = self::_getDateValue($startDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $startDate = (float) floor($startDate); + if (is_string($endDate = $eDate = self::_getDateValue($endDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $endDate = (float) floor($endDate); + + if ($sDate > $eDate) { + $startDate = $eDate; + $endDate = $sDate; + } + + // Execute function + $startDoW = 6 - self::DAYOFWEEK($startDate,2); + if ($startDoW < 0) { $startDoW = 0; } + $endDoW = self::DAYOFWEEK($endDate,2); + if ($endDoW >= 6) { $endDoW = 0; } + + $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5; + $partWeekDays = $endDoW + $startDoW; + if ($partWeekDays > 5) { + $partWeekDays -= 5; + } + + // Test any extra holiday parameters + $holidayCountedArray = array(); + foreach ($dateArgs as $holidayDate) { + if (is_string($holidayDate = self::_getDateValue($holidayDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { + if ((self::DAYOFWEEK($holidayDate,2) < 6) && (!in_array($holidayDate,$holidayCountedArray))) { + --$partWeekDays; + $holidayCountedArray[] = $holidayDate; + } + } + } + + if ($sDate > $eDate) { + return 0 - ($wholeWeekDays + $partWeekDays); + } + return $wholeWeekDays + $partWeekDays; + } // function NETWORKDAYS() + + + /** + * WORKDAY + * + * @param mixed Start date + * @param mixed number of days for adjustment + * @param array of mixed Optional Date Series + * @return long Interval between the dates + */ + public static function WORKDAY($startDate,$endDays) { + // Retrieve the mandatory start date and days that are referenced in the function definition + $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate); + $endDays = (int) PHPExcel_Calculation_Functions::flattenSingleValue($endDays); + // Flush the mandatory start date and days that are referenced in the function definition, and get the optional days + $dateArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + array_shift($dateArgs); + array_shift($dateArgs); + + if ((is_string($startDate = self::_getDateValue($startDate))) || (!is_numeric($endDays))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $startDate = (float) floor($startDate); + // If endDays is 0, we always return startDate + if ($endDays == 0) { return $startDate; } + + $decrementing = ($endDays < 0) ? True : False; + + // Adjust the start date if it falls over a weekend + + $startDoW = self::DAYOFWEEK($startDate,3); + if (self::DAYOFWEEK($startDate,3) >= 5) { + $startDate += ($decrementing) ? -$startDoW + 4: 7 - $startDoW; + ($decrementing) ? $endDays++ : $endDays--; + } + + // Add endDays + $endDate = (float) $startDate + (intval($endDays / 5) * 7) + ($endDays % 5); + + // Adjust the calculated end date if it falls over a weekend + $endDoW = self::DAYOFWEEK($endDate,3); + if ($endDoW >= 5) { + $endDate += ($decrementing) ? -$endDoW + 4: 7 - $endDoW; + } + + // Test any extra holiday parameters + if (count($dateArgs) > 0) { + $holidayCountedArray = $holidayDates = array(); + foreach ($dateArgs as $holidayDate) { + if ((!is_null($holidayDate)) && (trim($holidayDate) > '')) { + if (is_string($holidayDate = self::_getDateValue($holidayDate))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (self::DAYOFWEEK($holidayDate,3) < 5) { + $holidayDates[] = $holidayDate; + } + } + } + if ($decrementing) { + rsort($holidayDates, SORT_NUMERIC); + } else { + sort($holidayDates, SORT_NUMERIC); + } + foreach ($holidayDates as $holidayDate) { + if ($decrementing) { + if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) { + if (!in_array($holidayDate,$holidayCountedArray)) { + --$endDate; + $holidayCountedArray[] = $holidayDate; + } + } + } else { + if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { + if (!in_array($holidayDate,$holidayCountedArray)) { + ++$endDate; + $holidayCountedArray[] = $holidayDate; + } + } + } + // Adjust the calculated end date if it falls over a weekend + $endDoW = self::DAYOFWEEK($endDate,3); + if ($endDoW >= 5) { + $endDate += ($decrementing) ? -$endDoW + 4: 7 - $endDoW; + } + + } + } + + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + return (float) $endDate; + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + return PHPExcel_Shared_Date::ExcelToPHPObject($endDate); + break; + } + } // function WORKDAY() + + + /** + * DAYOFMONTH + * + * @param long $dateValue Excel date serial value or a standard date string + * @return int Day + */ + public static function DAYOFMONTH($dateValue = 1) { + $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue); + + if (is_string($dateValue = self::_getDateValue($dateValue))) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ($dateValue == 0.0) { + return 0; + } elseif ($dateValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); + + return (int) $PHPDateObject->format('j'); + } // function DAYOFMONTH() + + + /** + * DAYOFWEEK + * + * @param long $dateValue Excel date serial value or a standard date string + * @return int Day + */ + public static function DAYOFWEEK($dateValue = 1, $style = 1) { + $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue); + $style = floor(PHPExcel_Calculation_Functions::flattenSingleValue($style)); + + if (is_string($dateValue = self::_getDateValue($dateValue))) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ($dateValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); + $DoW = $PHPDateObject->format('w'); + + $firstDay = 1; + switch ($style) { + case 1: ++$DoW; + break; + case 2: if ($DoW == 0) { $DoW = 7; } + break; + case 3: if ($DoW == 0) { $DoW = 7; } + $firstDay = 0; + --$DoW; + break; + default: + } + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL) { + // Test for Excel's 1900 leap year, and introduce the error as required + if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) { + --$DoW; + if ($DoW < $firstDay) { + $DoW += 7; + } + } + } + + return (int) $DoW; + } // function DAYOFWEEK() + + + /** + * WEEKOFYEAR + * + * @param long $dateValue Excel date serial value or a standard date string + * @param boolean $method Week begins on Sunday or Monday + * @return int Week Number + */ + public static function WEEKOFYEAR($dateValue = 1, $method = 1) { + $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue); + $method = floor(PHPExcel_Calculation_Functions::flattenSingleValue($method)); + + if (!is_numeric($method)) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif (($method < 1) || ($method > 2)) { + return PHPExcel_Calculation_Functions::NaN(); + } + + if (is_string($dateValue = self::_getDateValue($dateValue))) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ($dateValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); + $dayOfYear = $PHPDateObject->format('z'); + $dow = $PHPDateObject->format('w'); + $PHPDateObject->modify('-'.$dayOfYear.' days'); + $dow = $PHPDateObject->format('w'); + $daysInFirstWeek = 7 - (($dow + (2 - $method)) % 7); + $dayOfYear -= $daysInFirstWeek; + $weekOfYear = ceil($dayOfYear / 7) + 1; + + return (int) $weekOfYear; + } // function WEEKOFYEAR() + + + /** + * MONTHOFYEAR + * + * @param long $dateValue Excel date serial value or a standard date string + * @return int Month + */ + public static function MONTHOFYEAR($dateValue = 1) { + $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue); + + if (is_string($dateValue = self::_getDateValue($dateValue))) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ($dateValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); + + return (int) $PHPDateObject->format('n'); + } // function MONTHOFYEAR() + + + /** + * YEAR + * + * @param long $dateValue Excel date serial value or a standard date string + * @return int Year + */ + public static function YEAR($dateValue = 1) { + $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue); + + if (is_string($dateValue = self::_getDateValue($dateValue))) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ($dateValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Execute function + $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); + + return (int) $PHPDateObject->format('Y'); + } // function YEAR() + + + /** + * HOUROFDAY + * + * @param mixed $timeValue Excel time serial value or a standard time string + * @return int Hour + */ + public static function HOUROFDAY($timeValue = 0) { + $timeValue = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue); + + if (!is_numeric($timeValue)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $testVal = strtok($timeValue,'/-: '); + if (strlen($testVal) < strlen($timeValue)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + $timeValue = self::_getTimeValue($timeValue); + if (is_string($timeValue)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + // Execute function + if ($timeValue >= 1) { + $timeValue = fmod($timeValue,1); + } elseif ($timeValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue); + + return (int) gmdate('G',$timeValue); + } // function HOUROFDAY() + + + /** + * MINUTEOFHOUR + * + * @param long $timeValue Excel time serial value or a standard time string + * @return int Minute + */ + public static function MINUTEOFHOUR($timeValue = 0) { + $timeValue = $timeTester = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue); + + if (!is_numeric($timeValue)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $testVal = strtok($timeValue,'/-: '); + if (strlen($testVal) < strlen($timeValue)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + $timeValue = self::_getTimeValue($timeValue); + if (is_string($timeValue)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + // Execute function + if ($timeValue >= 1) { + $timeValue = fmod($timeValue,1); + } elseif ($timeValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue); + + return (int) gmdate('i',$timeValue); + } // function MINUTEOFHOUR() + + + /** + * SECONDOFMINUTE + * + * @param long $timeValue Excel time serial value or a standard time string + * @return int Second + */ + public static function SECONDOFMINUTE($timeValue = 0) { + $timeValue = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue); + + if (!is_numeric($timeValue)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $testVal = strtok($timeValue,'/-: '); + if (strlen($testVal) < strlen($timeValue)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + $timeValue = self::_getTimeValue($timeValue); + if (is_string($timeValue)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + // Execute function + if ($timeValue >= 1) { + $timeValue = fmod($timeValue,1); + } elseif ($timeValue < 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue); + + return (int) gmdate('s',$timeValue); + } // function SECONDOFMINUTE() + + + /** + * EDATE + * + * Returns the serial number that represents the date that is the indicated number of months before or after a specified date + * (the start_date). Use EDATE to calculate maturity dates or due dates that fall on the same day of the month as the date of issue. + * + * @param long $dateValue Excel date serial value or a standard date string + * @param int $adjustmentMonths Number of months to adjust by + * @return long Excel date serial value + */ + public static function EDATE($dateValue = 1, $adjustmentMonths = 0) { + $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue); + $adjustmentMonths = floor(PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths)); + + if (!is_numeric($adjustmentMonths)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (is_string($dateValue = self::_getDateValue($dateValue))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Execute function + $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths); + + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject)); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + return $PHPDateObject; + break; + } + } // function EDATE() + + + /** + * EOMONTH + * + * Returns the serial number for the last day of the month that is the indicated number of months before or after start_date. + * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month. + * + * @param long $dateValue Excel date serial value or a standard date string + * @param int $adjustmentMonths Number of months to adjust by + * @return long Excel date serial value + */ + public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0) { + $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue); + $adjustmentMonths = floor(PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths)); + + if (!is_numeric($adjustmentMonths)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (is_string($dateValue = self::_getDateValue($dateValue))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Execute function + $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths+1); + $adjustDays = (int) $PHPDateObject->format('d'); + $adjustDaysString = '-'.$adjustDays.' days'; + $PHPDateObject->modify($adjustDaysString); + + switch (PHPExcel_Calculation_Functions::getReturnDateType()) { + case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL : + return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC : + return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject)); + break; + case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT : + return $PHPDateObject; + break; + } + } // function EOMONTH() + +} // class PHPExcel_Calculation_DateTime diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Engineering.php b/libraries/PHPExcel/PHPExcel/Calculation/Engineering.php new file mode 100644 index 000000000..9adc2ecdf --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/Engineering.php @@ -0,0 +1,2174 @@ + array( 'Group' => 'Mass', 'Unit Name' => 'Gram', 'AllowPrefix' => True ), + 'sg' => array( 'Group' => 'Mass', 'Unit Name' => 'Slug', 'AllowPrefix' => False ), + 'lbm' => array( 'Group' => 'Mass', 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => False ), + 'u' => array( 'Group' => 'Mass', 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => True ), + 'ozm' => array( 'Group' => 'Mass', 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => False ), + 'm' => array( 'Group' => 'Distance', 'Unit Name' => 'Meter', 'AllowPrefix' => True ), + 'mi' => array( 'Group' => 'Distance', 'Unit Name' => 'Statute mile', 'AllowPrefix' => False ), + 'Nmi' => array( 'Group' => 'Distance', 'Unit Name' => 'Nautical mile', 'AllowPrefix' => False ), + 'in' => array( 'Group' => 'Distance', 'Unit Name' => 'Inch', 'AllowPrefix' => False ), + 'ft' => array( 'Group' => 'Distance', 'Unit Name' => 'Foot', 'AllowPrefix' => False ), + 'yd' => array( 'Group' => 'Distance', 'Unit Name' => 'Yard', 'AllowPrefix' => False ), + 'ang' => array( 'Group' => 'Distance', 'Unit Name' => 'Angstrom', 'AllowPrefix' => True ), + 'Pica' => array( 'Group' => 'Distance', 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => False ), + 'yr' => array( 'Group' => 'Time', 'Unit Name' => 'Year', 'AllowPrefix' => False ), + 'day' => array( 'Group' => 'Time', 'Unit Name' => 'Day', 'AllowPrefix' => False ), + 'hr' => array( 'Group' => 'Time', 'Unit Name' => 'Hour', 'AllowPrefix' => False ), + 'mn' => array( 'Group' => 'Time', 'Unit Name' => 'Minute', 'AllowPrefix' => False ), + 'sec' => array( 'Group' => 'Time', 'Unit Name' => 'Second', 'AllowPrefix' => True ), + 'Pa' => array( 'Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => True ), + 'p' => array( 'Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => True ), + 'atm' => array( 'Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => True ), + 'at' => array( 'Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => True ), + 'mmHg' => array( 'Group' => 'Pressure', 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => True ), + 'N' => array( 'Group' => 'Force', 'Unit Name' => 'Newton', 'AllowPrefix' => True ), + 'dyn' => array( 'Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => True ), + 'dy' => array( 'Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => True ), + 'lbf' => array( 'Group' => 'Force', 'Unit Name' => 'Pound force', 'AllowPrefix' => False ), + 'J' => array( 'Group' => 'Energy', 'Unit Name' => 'Joule', 'AllowPrefix' => True ), + 'e' => array( 'Group' => 'Energy', 'Unit Name' => 'Erg', 'AllowPrefix' => True ), + 'c' => array( 'Group' => 'Energy', 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => True ), + 'cal' => array( 'Group' => 'Energy', 'Unit Name' => 'IT calorie', 'AllowPrefix' => True ), + 'eV' => array( 'Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => True ), + 'ev' => array( 'Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => True ), + 'HPh' => array( 'Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => False ), + 'hh' => array( 'Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => False ), + 'Wh' => array( 'Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => True ), + 'wh' => array( 'Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => True ), + 'flb' => array( 'Group' => 'Energy', 'Unit Name' => 'Foot-pound', 'AllowPrefix' => False ), + 'BTU' => array( 'Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => False ), + 'btu' => array( 'Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => False ), + 'HP' => array( 'Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => False ), + 'h' => array( 'Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => False ), + 'W' => array( 'Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => True ), + 'w' => array( 'Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => True ), + 'T' => array( 'Group' => 'Magnetism', 'Unit Name' => 'Tesla', 'AllowPrefix' => True ), + 'ga' => array( 'Group' => 'Magnetism', 'Unit Name' => 'Gauss', 'AllowPrefix' => True ), + 'C' => array( 'Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => False ), + 'cel' => array( 'Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => False ), + 'F' => array( 'Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => False ), + 'fah' => array( 'Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => False ), + 'K' => array( 'Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => False ), + 'kel' => array( 'Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => False ), + 'tsp' => array( 'Group' => 'Liquid', 'Unit Name' => 'Teaspoon', 'AllowPrefix' => False ), + 'tbs' => array( 'Group' => 'Liquid', 'Unit Name' => 'Tablespoon', 'AllowPrefix' => False ), + 'oz' => array( 'Group' => 'Liquid', 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => False ), + 'cup' => array( 'Group' => 'Liquid', 'Unit Name' => 'Cup', 'AllowPrefix' => False ), + 'pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => False ), + 'us_pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => False ), + 'uk_pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => False ), + 'qt' => array( 'Group' => 'Liquid', 'Unit Name' => 'Quart', 'AllowPrefix' => False ), + 'gal' => array( 'Group' => 'Liquid', 'Unit Name' => 'Gallon', 'AllowPrefix' => False ), + 'l' => array( 'Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => True ), + 'lt' => array( 'Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => True ) + ); + + private static $_conversionMultipliers = array( 'Y' => array( 'multiplier' => 1E24, 'name' => 'yotta' ), + 'Z' => array( 'multiplier' => 1E21, 'name' => 'zetta' ), + 'E' => array( 'multiplier' => 1E18, 'name' => 'exa' ), + 'P' => array( 'multiplier' => 1E15, 'name' => 'peta' ), + 'T' => array( 'multiplier' => 1E12, 'name' => 'tera' ), + 'G' => array( 'multiplier' => 1E9, 'name' => 'giga' ), + 'M' => array( 'multiplier' => 1E6, 'name' => 'mega' ), + 'k' => array( 'multiplier' => 1E3, 'name' => 'kilo' ), + 'h' => array( 'multiplier' => 1E2, 'name' => 'hecto' ), + 'e' => array( 'multiplier' => 1E1, 'name' => 'deka' ), + 'd' => array( 'multiplier' => 1E-1, 'name' => 'deci' ), + 'c' => array( 'multiplier' => 1E-2, 'name' => 'centi' ), + 'm' => array( 'multiplier' => 1E-3, 'name' => 'milli' ), + 'u' => array( 'multiplier' => 1E-6, 'name' => 'micro' ), + 'n' => array( 'multiplier' => 1E-9, 'name' => 'nano' ), + 'p' => array( 'multiplier' => 1E-12, 'name' => 'pico' ), + 'f' => array( 'multiplier' => 1E-15, 'name' => 'femto' ), + 'a' => array( 'multiplier' => 1E-18, 'name' => 'atto' ), + 'z' => array( 'multiplier' => 1E-21, 'name' => 'zepto' ), + 'y' => array( 'multiplier' => 1E-24, 'name' => 'yocto' ) + ); + + private static $_unitConversions = array( 'Mass' => array( 'g' => array( 'g' => 1.0, + 'sg' => 6.85220500053478E-05, + 'lbm' => 2.20462291469134E-03, + 'u' => 6.02217000000000E+23, + 'ozm' => 3.52739718003627E-02 + ), + 'sg' => array( 'g' => 1.45938424189287E+04, + 'sg' => 1.0, + 'lbm' => 3.21739194101647E+01, + 'u' => 8.78866000000000E+27, + 'ozm' => 5.14782785944229E+02 + ), + 'lbm' => array( 'g' => 4.5359230974881148E+02, + 'sg' => 3.10810749306493E-02, + 'lbm' => 1.0, + 'u' => 2.73161000000000E+26, + 'ozm' => 1.60000023429410E+01 + ), + 'u' => array( 'g' => 1.66053100460465E-24, + 'sg' => 1.13782988532950E-28, + 'lbm' => 3.66084470330684E-27, + 'u' => 1.0, + 'ozm' => 5.85735238300524E-26 + ), + 'ozm' => array( 'g' => 2.83495152079732E+01, + 'sg' => 1.94256689870811E-03, + 'lbm' => 6.24999908478882E-02, + 'u' => 1.70725600000000E+25, + 'ozm' => 1.0 + ) + ), + 'Distance' => array( 'm' => array( 'm' => 1.0, + 'mi' => 6.21371192237334E-04, + 'Nmi' => 5.39956803455724E-04, + 'in' => 3.93700787401575E+01, + 'ft' => 3.28083989501312E+00, + 'yd' => 1.09361329797891E+00, + 'ang' => 1.00000000000000E+10, + 'Pica' => 2.83464566929116E+03 + ), + 'mi' => array( 'm' => 1.60934400000000E+03, + 'mi' => 1.0, + 'Nmi' => 8.68976241900648E-01, + 'in' => 6.33600000000000E+04, + 'ft' => 5.28000000000000E+03, + 'yd' => 1.76000000000000E+03, + 'ang' => 1.60934400000000E+13, + 'Pica' => 4.56191999999971E+06 + ), + 'Nmi' => array( 'm' => 1.85200000000000E+03, + 'mi' => 1.15077944802354E+00, + 'Nmi' => 1.0, + 'in' => 7.29133858267717E+04, + 'ft' => 6.07611548556430E+03, + 'yd' => 2.02537182785694E+03, + 'ang' => 1.85200000000000E+13, + 'Pica' => 5.24976377952723E+06 + ), + 'in' => array( 'm' => 2.54000000000000E-02, + 'mi' => 1.57828282828283E-05, + 'Nmi' => 1.37149028077754E-05, + 'in' => 1.0, + 'ft' => 8.33333333333333E-02, + 'yd' => 2.77777777686643E-02, + 'ang' => 2.54000000000000E+08, + 'Pica' => 7.19999999999955E+01 + ), + 'ft' => array( 'm' => 3.04800000000000E-01, + 'mi' => 1.89393939393939E-04, + 'Nmi' => 1.64578833693305E-04, + 'in' => 1.20000000000000E+01, + 'ft' => 1.0, + 'yd' => 3.33333333223972E-01, + 'ang' => 3.04800000000000E+09, + 'Pica' => 8.63999999999946E+02 + ), + 'yd' => array( 'm' => 9.14400000300000E-01, + 'mi' => 5.68181818368230E-04, + 'Nmi' => 4.93736501241901E-04, + 'in' => 3.60000000118110E+01, + 'ft' => 3.00000000000000E+00, + 'yd' => 1.0, + 'ang' => 9.14400000300000E+09, + 'Pica' => 2.59200000085023E+03 + ), + 'ang' => array( 'm' => 1.00000000000000E-10, + 'mi' => 6.21371192237334E-14, + 'Nmi' => 5.39956803455724E-14, + 'in' => 3.93700787401575E-09, + 'ft' => 3.28083989501312E-10, + 'yd' => 1.09361329797891E-10, + 'ang' => 1.0, + 'Pica' => 2.83464566929116E-07 + ), + 'Pica' => array( 'm' => 3.52777777777800E-04, + 'mi' => 2.19205948372629E-07, + 'Nmi' => 1.90484761219114E-07, + 'in' => 1.38888888888898E-02, + 'ft' => 1.15740740740748E-03, + 'yd' => 3.85802469009251E-04, + 'ang' => 3.52777777777800E+06, + 'Pica' => 1.0 + ) + ), + 'Time' => array( 'yr' => array( 'yr' => 1.0, + 'day' => 365.25, + 'hr' => 8766.0, + 'mn' => 525960.0, + 'sec' => 31557600.0 + ), + 'day' => array( 'yr' => 2.73785078713210E-03, + 'day' => 1.0, + 'hr' => 24.0, + 'mn' => 1440.0, + 'sec' => 86400.0 + ), + 'hr' => array( 'yr' => 1.14077116130504E-04, + 'day' => 4.16666666666667E-02, + 'hr' => 1.0, + 'mn' => 60.0, + 'sec' => 3600.0 + ), + 'mn' => array( 'yr' => 1.90128526884174E-06, + 'day' => 6.94444444444444E-04, + 'hr' => 1.66666666666667E-02, + 'mn' => 1.0, + 'sec' => 60.0 + ), + 'sec' => array( 'yr' => 3.16880878140289E-08, + 'day' => 1.15740740740741E-05, + 'hr' => 2.77777777777778E-04, + 'mn' => 1.66666666666667E-02, + 'sec' => 1.0 + ) + ), + 'Pressure' => array( 'Pa' => array( 'Pa' => 1.0, + 'p' => 1.0, + 'atm' => 9.86923299998193E-06, + 'at' => 9.86923299998193E-06, + 'mmHg' => 7.50061707998627E-03 + ), + 'p' => array( 'Pa' => 1.0, + 'p' => 1.0, + 'atm' => 9.86923299998193E-06, + 'at' => 9.86923299998193E-06, + 'mmHg' => 7.50061707998627E-03 + ), + 'atm' => array( 'Pa' => 1.01324996583000E+05, + 'p' => 1.01324996583000E+05, + 'atm' => 1.0, + 'at' => 1.0, + 'mmHg' => 760.0 + ), + 'at' => array( 'Pa' => 1.01324996583000E+05, + 'p' => 1.01324996583000E+05, + 'atm' => 1.0, + 'at' => 1.0, + 'mmHg' => 760.0 + ), + 'mmHg' => array( 'Pa' => 1.33322363925000E+02, + 'p' => 1.33322363925000E+02, + 'atm' => 1.31578947368421E-03, + 'at' => 1.31578947368421E-03, + 'mmHg' => 1.0 + ) + ), + 'Force' => array( 'N' => array( 'N' => 1.0, + 'dyn' => 1.0E+5, + 'dy' => 1.0E+5, + 'lbf' => 2.24808923655339E-01 + ), + 'dyn' => array( 'N' => 1.0E-5, + 'dyn' => 1.0, + 'dy' => 1.0, + 'lbf' => 2.24808923655339E-06 + ), + 'dy' => array( 'N' => 1.0E-5, + 'dyn' => 1.0, + 'dy' => 1.0, + 'lbf' => 2.24808923655339E-06 + ), + 'lbf' => array( 'N' => 4.448222, + 'dyn' => 4.448222E+5, + 'dy' => 4.448222E+5, + 'lbf' => 1.0 + ) + ), + 'Energy' => array( 'J' => array( 'J' => 1.0, + 'e' => 9.99999519343231E+06, + 'c' => 2.39006249473467E-01, + 'cal' => 2.38846190642017E-01, + 'eV' => 6.24145700000000E+18, + 'ev' => 6.24145700000000E+18, + 'HPh' => 3.72506430801000E-07, + 'hh' => 3.72506430801000E-07, + 'Wh' => 2.77777916238711E-04, + 'wh' => 2.77777916238711E-04, + 'flb' => 2.37304222192651E+01, + 'BTU' => 9.47815067349015E-04, + 'btu' => 9.47815067349015E-04 + ), + 'e' => array( 'J' => 1.00000048065700E-07, + 'e' => 1.0, + 'c' => 2.39006364353494E-08, + 'cal' => 2.38846305445111E-08, + 'eV' => 6.24146000000000E+11, + 'ev' => 6.24146000000000E+11, + 'HPh' => 3.72506609848824E-14, + 'hh' => 3.72506609848824E-14, + 'Wh' => 2.77778049754611E-11, + 'wh' => 2.77778049754611E-11, + 'flb' => 2.37304336254586E-06, + 'BTU' => 9.47815522922962E-11, + 'btu' => 9.47815522922962E-11 + ), + 'c' => array( 'J' => 4.18399101363672E+00, + 'e' => 4.18398900257312E+07, + 'c' => 1.0, + 'cal' => 9.99330315287563E-01, + 'eV' => 2.61142000000000E+19, + 'ev' => 2.61142000000000E+19, + 'HPh' => 1.55856355899327E-06, + 'hh' => 1.55856355899327E-06, + 'Wh' => 1.16222030532950E-03, + 'wh' => 1.16222030532950E-03, + 'flb' => 9.92878733152102E+01, + 'BTU' => 3.96564972437776E-03, + 'btu' => 3.96564972437776E-03 + ), + 'cal' => array( 'J' => 4.18679484613929E+00, + 'e' => 4.18679283372801E+07, + 'c' => 1.00067013349059E+00, + 'cal' => 1.0, + 'eV' => 2.61317000000000E+19, + 'ev' => 2.61317000000000E+19, + 'HPh' => 1.55960800463137E-06, + 'hh' => 1.55960800463137E-06, + 'Wh' => 1.16299914807955E-03, + 'wh' => 1.16299914807955E-03, + 'flb' => 9.93544094443283E+01, + 'BTU' => 3.96830723907002E-03, + 'btu' => 3.96830723907002E-03 + ), + 'eV' => array( 'J' => 1.60219000146921E-19, + 'e' => 1.60218923136574E-12, + 'c' => 3.82933423195043E-20, + 'cal' => 3.82676978535648E-20, + 'eV' => 1.0, + 'ev' => 1.0, + 'HPh' => 5.96826078912344E-26, + 'hh' => 5.96826078912344E-26, + 'Wh' => 4.45053000026614E-23, + 'wh' => 4.45053000026614E-23, + 'flb' => 3.80206452103492E-18, + 'BTU' => 1.51857982414846E-22, + 'btu' => 1.51857982414846E-22 + ), + 'ev' => array( 'J' => 1.60219000146921E-19, + 'e' => 1.60218923136574E-12, + 'c' => 3.82933423195043E-20, + 'cal' => 3.82676978535648E-20, + 'eV' => 1.0, + 'ev' => 1.0, + 'HPh' => 5.96826078912344E-26, + 'hh' => 5.96826078912344E-26, + 'Wh' => 4.45053000026614E-23, + 'wh' => 4.45053000026614E-23, + 'flb' => 3.80206452103492E-18, + 'BTU' => 1.51857982414846E-22, + 'btu' => 1.51857982414846E-22 + ), + 'HPh' => array( 'J' => 2.68451741316170E+06, + 'e' => 2.68451612283024E+13, + 'c' => 6.41616438565991E+05, + 'cal' => 6.41186757845835E+05, + 'eV' => 1.67553000000000E+25, + 'ev' => 1.67553000000000E+25, + 'HPh' => 1.0, + 'hh' => 1.0, + 'Wh' => 7.45699653134593E+02, + 'wh' => 7.45699653134593E+02, + 'flb' => 6.37047316692964E+07, + 'BTU' => 2.54442605275546E+03, + 'btu' => 2.54442605275546E+03 + ), + 'hh' => array( 'J' => 2.68451741316170E+06, + 'e' => 2.68451612283024E+13, + 'c' => 6.41616438565991E+05, + 'cal' => 6.41186757845835E+05, + 'eV' => 1.67553000000000E+25, + 'ev' => 1.67553000000000E+25, + 'HPh' => 1.0, + 'hh' => 1.0, + 'Wh' => 7.45699653134593E+02, + 'wh' => 7.45699653134593E+02, + 'flb' => 6.37047316692964E+07, + 'BTU' => 2.54442605275546E+03, + 'btu' => 2.54442605275546E+03 + ), + 'Wh' => array( 'J' => 3.59999820554720E+03, + 'e' => 3.59999647518369E+10, + 'c' => 8.60422069219046E+02, + 'cal' => 8.59845857713046E+02, + 'eV' => 2.24692340000000E+22, + 'ev' => 2.24692340000000E+22, + 'HPh' => 1.34102248243839E-03, + 'hh' => 1.34102248243839E-03, + 'Wh' => 1.0, + 'wh' => 1.0, + 'flb' => 8.54294774062316E+04, + 'BTU' => 3.41213254164705E+00, + 'btu' => 3.41213254164705E+00 + ), + 'wh' => array( 'J' => 3.59999820554720E+03, + 'e' => 3.59999647518369E+10, + 'c' => 8.60422069219046E+02, + 'cal' => 8.59845857713046E+02, + 'eV' => 2.24692340000000E+22, + 'ev' => 2.24692340000000E+22, + 'HPh' => 1.34102248243839E-03, + 'hh' => 1.34102248243839E-03, + 'Wh' => 1.0, + 'wh' => 1.0, + 'flb' => 8.54294774062316E+04, + 'BTU' => 3.41213254164705E+00, + 'btu' => 3.41213254164705E+00 + ), + 'flb' => array( 'J' => 4.21400003236424E-02, + 'e' => 4.21399800687660E+05, + 'c' => 1.00717234301644E-02, + 'cal' => 1.00649785509554E-02, + 'eV' => 2.63015000000000E+17, + 'ev' => 2.63015000000000E+17, + 'HPh' => 1.56974211145130E-08, + 'hh' => 1.56974211145130E-08, + 'Wh' => 1.17055614802000E-05, + 'wh' => 1.17055614802000E-05, + 'flb' => 1.0, + 'BTU' => 3.99409272448406E-05, + 'btu' => 3.99409272448406E-05 + ), + 'BTU' => array( 'J' => 1.05505813786749E+03, + 'e' => 1.05505763074665E+10, + 'c' => 2.52165488508168E+02, + 'cal' => 2.51996617135510E+02, + 'eV' => 6.58510000000000E+21, + 'ev' => 6.58510000000000E+21, + 'HPh' => 3.93015941224568E-04, + 'hh' => 3.93015941224568E-04, + 'Wh' => 2.93071851047526E-01, + 'wh' => 2.93071851047526E-01, + 'flb' => 2.50369750774671E+04, + 'BTU' => 1.0, + 'btu' => 1.0, + ), + 'btu' => array( 'J' => 1.05505813786749E+03, + 'e' => 1.05505763074665E+10, + 'c' => 2.52165488508168E+02, + 'cal' => 2.51996617135510E+02, + 'eV' => 6.58510000000000E+21, + 'ev' => 6.58510000000000E+21, + 'HPh' => 3.93015941224568E-04, + 'hh' => 3.93015941224568E-04, + 'Wh' => 2.93071851047526E-01, + 'wh' => 2.93071851047526E-01, + 'flb' => 2.50369750774671E+04, + 'BTU' => 1.0, + 'btu' => 1.0, + ) + ), + 'Power' => array( 'HP' => array( 'HP' => 1.0, + 'h' => 1.0, + 'W' => 7.45701000000000E+02, + 'w' => 7.45701000000000E+02 + ), + 'h' => array( 'HP' => 1.0, + 'h' => 1.0, + 'W' => 7.45701000000000E+02, + 'w' => 7.45701000000000E+02 + ), + 'W' => array( 'HP' => 1.34102006031908E-03, + 'h' => 1.34102006031908E-03, + 'W' => 1.0, + 'w' => 1.0 + ), + 'w' => array( 'HP' => 1.34102006031908E-03, + 'h' => 1.34102006031908E-03, + 'W' => 1.0, + 'w' => 1.0 + ) + ), + 'Magnetism' => array( 'T' => array( 'T' => 1.0, + 'ga' => 10000.0 + ), + 'ga' => array( 'T' => 0.0001, + 'ga' => 1.0 + ) + ), + 'Liquid' => array( 'tsp' => array( 'tsp' => 1.0, + 'tbs' => 3.33333333333333E-01, + 'oz' => 1.66666666666667E-01, + 'cup' => 2.08333333333333E-02, + 'pt' => 1.04166666666667E-02, + 'us_pt' => 1.04166666666667E-02, + 'uk_pt' => 8.67558516821960E-03, + 'qt' => 5.20833333333333E-03, + 'gal' => 1.30208333333333E-03, + 'l' => 4.92999408400710E-03, + 'lt' => 4.92999408400710E-03 + ), + 'tbs' => array( 'tsp' => 3.00000000000000E+00, + 'tbs' => 1.0, + 'oz' => 5.00000000000000E-01, + 'cup' => 6.25000000000000E-02, + 'pt' => 3.12500000000000E-02, + 'us_pt' => 3.12500000000000E-02, + 'uk_pt' => 2.60267555046588E-02, + 'qt' => 1.56250000000000E-02, + 'gal' => 3.90625000000000E-03, + 'l' => 1.47899822520213E-02, + 'lt' => 1.47899822520213E-02 + ), + 'oz' => array( 'tsp' => 6.00000000000000E+00, + 'tbs' => 2.00000000000000E+00, + 'oz' => 1.0, + 'cup' => 1.25000000000000E-01, + 'pt' => 6.25000000000000E-02, + 'us_pt' => 6.25000000000000E-02, + 'uk_pt' => 5.20535110093176E-02, + 'qt' => 3.12500000000000E-02, + 'gal' => 7.81250000000000E-03, + 'l' => 2.95799645040426E-02, + 'lt' => 2.95799645040426E-02 + ), + 'cup' => array( 'tsp' => 4.80000000000000E+01, + 'tbs' => 1.60000000000000E+01, + 'oz' => 8.00000000000000E+00, + 'cup' => 1.0, + 'pt' => 5.00000000000000E-01, + 'us_pt' => 5.00000000000000E-01, + 'uk_pt' => 4.16428088074541E-01, + 'qt' => 2.50000000000000E-01, + 'gal' => 6.25000000000000E-02, + 'l' => 2.36639716032341E-01, + 'lt' => 2.36639716032341E-01 + ), + 'pt' => array( 'tsp' => 9.60000000000000E+01, + 'tbs' => 3.20000000000000E+01, + 'oz' => 1.60000000000000E+01, + 'cup' => 2.00000000000000E+00, + 'pt' => 1.0, + 'us_pt' => 1.0, + 'uk_pt' => 8.32856176149081E-01, + 'qt' => 5.00000000000000E-01, + 'gal' => 1.25000000000000E-01, + 'l' => 4.73279432064682E-01, + 'lt' => 4.73279432064682E-01 + ), + 'us_pt' => array( 'tsp' => 9.60000000000000E+01, + 'tbs' => 3.20000000000000E+01, + 'oz' => 1.60000000000000E+01, + 'cup' => 2.00000000000000E+00, + 'pt' => 1.0, + 'us_pt' => 1.0, + 'uk_pt' => 8.32856176149081E-01, + 'qt' => 5.00000000000000E-01, + 'gal' => 1.25000000000000E-01, + 'l' => 4.73279432064682E-01, + 'lt' => 4.73279432064682E-01 + ), + 'uk_pt' => array( 'tsp' => 1.15266000000000E+02, + 'tbs' => 3.84220000000000E+01, + 'oz' => 1.92110000000000E+01, + 'cup' => 2.40137500000000E+00, + 'pt' => 1.20068750000000E+00, + 'us_pt' => 1.20068750000000E+00, + 'uk_pt' => 1.0, + 'qt' => 6.00343750000000E-01, + 'gal' => 1.50085937500000E-01, + 'l' => 5.68260698087162E-01, + 'lt' => 5.68260698087162E-01 + ), + 'qt' => array( 'tsp' => 1.92000000000000E+02, + 'tbs' => 6.40000000000000E+01, + 'oz' => 3.20000000000000E+01, + 'cup' => 4.00000000000000E+00, + 'pt' => 2.00000000000000E+00, + 'us_pt' => 2.00000000000000E+00, + 'uk_pt' => 1.66571235229816E+00, + 'qt' => 1.0, + 'gal' => 2.50000000000000E-01, + 'l' => 9.46558864129363E-01, + 'lt' => 9.46558864129363E-01 + ), + 'gal' => array( 'tsp' => 7.68000000000000E+02, + 'tbs' => 2.56000000000000E+02, + 'oz' => 1.28000000000000E+02, + 'cup' => 1.60000000000000E+01, + 'pt' => 8.00000000000000E+00, + 'us_pt' => 8.00000000000000E+00, + 'uk_pt' => 6.66284940919265E+00, + 'qt' => 4.00000000000000E+00, + 'gal' => 1.0, + 'l' => 3.78623545651745E+00, + 'lt' => 3.78623545651745E+00 + ), + 'l' => array( 'tsp' => 2.02840000000000E+02, + 'tbs' => 6.76133333333333E+01, + 'oz' => 3.38066666666667E+01, + 'cup' => 4.22583333333333E+00, + 'pt' => 2.11291666666667E+00, + 'us_pt' => 2.11291666666667E+00, + 'uk_pt' => 1.75975569552166E+00, + 'qt' => 1.05645833333333E+00, + 'gal' => 2.64114583333333E-01, + 'l' => 1.0, + 'lt' => 1.0 + ), + 'lt' => array( 'tsp' => 2.02840000000000E+02, + 'tbs' => 6.76133333333333E+01, + 'oz' => 3.38066666666667E+01, + 'cup' => 4.22583333333333E+00, + 'pt' => 2.11291666666667E+00, + 'us_pt' => 2.11291666666667E+00, + 'uk_pt' => 1.75975569552166E+00, + 'qt' => 1.05645833333333E+00, + 'gal' => 2.64114583333333E-01, + 'l' => 1.0, + 'lt' => 1.0 + ) + ) + ); + + + public static function _parseComplex($complexNumber) { + $workString = (string) $complexNumber; + + $realNumber = $imaginary = 0; + // Extract the suffix, if there is one + $suffix = substr($workString,-1); + if (!is_numeric($suffix)) { + $workString = substr($workString,0,-1); + } else { + $suffix = ''; + } + + // Split the input into its Real and Imaginary components + $leadingSign = 0; + if (strlen($workString) > 0) { + $leadingSign = (($workString{0} == '+') || ($workString{0} == '-')) ? 1 : 0; + } + $power = ''; + $realNumber = strtok($workString, '+-'); + if (strtoupper(substr($realNumber,-1)) == 'E') { + $power = strtok('+-'); + ++$leadingSign; + } + + $realNumber = substr($workString,0,strlen($realNumber)+strlen($power)+$leadingSign); + + if ($suffix != '') { + $imaginary = substr($workString,strlen($realNumber)); + + if (($imaginary == '') && (($realNumber == '') || ($realNumber == '+') || ($realNumber == '-'))) { + $imaginary = $realNumber.'1'; + $realNumber = '0'; + } else if ($imaginary == '') { + $imaginary = $realNumber; + $realNumber = '0'; + } elseif (($imaginary == '+') || ($imaginary == '-')) { + $imaginary .= '1'; + } + } + + return array( 'real' => $realNumber, + 'imaginary' => $imaginary, + 'suffix' => $suffix + ); + } // function _parseComplex() + + + private static function _cleanComplex($complexNumber) { + if ($complexNumber{0} == '+') $complexNumber = substr($complexNumber,1); + if ($complexNumber{0} == '0') $complexNumber = substr($complexNumber,1); + if ($complexNumber{0} == '.') $complexNumber = '0'.$complexNumber; + if ($complexNumber{0} == '+') $complexNumber = substr($complexNumber,1); + return $complexNumber; + } + + + private static function _nbrConversionFormat($xVal,$places) { + if (!is_null($places)) { + if (strlen($xVal) <= $places) { + return substr(str_pad($xVal,$places,'0',STR_PAD_LEFT),-10); + } else { + return PHPExcel_Calculation_Functions::NaN(); + } + } + + return substr($xVal,-10); + } // function _nbrConversionFormat() + + + /** + * BESSELI + * + * Returns the modified Bessel function, which is equivalent to the Bessel function evaluated for purely imaginary arguments + * + * @param float $x + * @param float $n + * @return int + */ + public static function BESSELI($x, $n) { + $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x); + $n = (is_null($n)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($n); + + if ((is_numeric($x)) && (is_numeric($n))) { + $n = floor($n); + if ($n < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $f_2_PI = 2 * M_PI; + + if (abs($x) <= 30) { + $fTerm = pow($x / 2, $n) / PHPExcel_Calculation_MathTrig::FACT($n); + $nK = 1; + $fResult = $fTerm; + $fSqrX = ($x * $x) / 4; + do { + $fTerm *= $fSqrX; + $fTerm /= ($nK * ($nK + $n)); + $fResult += $fTerm; + } while ((abs($fTerm) > 1e-10) && (++$nK < 100)); + } else { + $fXAbs = abs($x); + $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs); + if (($n && 1) && ($x < 0)) { + $fResult = -$fResult; + } + } + return $fResult; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function BESSELI() + + + /** + * BESSELJ + * + * Returns the Bessel function + * + * @param float $x + * @param float $n + * @return int + */ + public static function BESSELJ($x, $n) { + $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x); + $n = (is_null($n)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($n); + + if ((is_numeric($x)) && (is_numeric($n))) { + $n = floor($n); + if ($n < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $f_PI_DIV_2 = M_PI / 2; + $f_PI_DIV_4 = M_PI / 4; + + $fResult = 0; + if (abs($x) <= 30) { + $fTerm = pow($x / 2, $n) / PHPExcel_Calculation_MathTrig::FACT($n); + $nK = 1; + $fResult = $fTerm; + $fSqrX = ($x * $x) / -4; + do { + $fTerm *= $fSqrX; + $fTerm /= ($nK * ($nK + $n)); + $fResult += $fTerm; + } while ((abs($fTerm) > 1e-10) && (++$nK < 100)); + } else { + $fXAbs = abs($x); + $fResult = sqrt(M_2DIVPI / $fXAbs) * cos($fXAbs - $n * $f_PI_DIV_2 - $f_PI_DIV_4); + if (($n && 1) && ($x < 0)) { + $fResult = -$fResult; + } + } + return $fResult; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function BESSELJ() + + + private static function _Besselk0($fNum) { + if ($fNum <= 2) { + $fNum2 = $fNum * 0.5; + $y = ($fNum2 * $fNum2); + $fRet = -log($fNum2) * self::BESSELI($fNum, 0) + + (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y * + (0.10750e-3 + $y * 0.74e-5)))))); + } else { + $y = 2 / $fNum; + $fRet = exp(-$fNum) / sqrt($fNum) * + (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y * + (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3)))))); + } + return $fRet; + } // function _Besselk0() + + + private static function _Besselk1($fNum) { + if ($fNum <= 2) { + $fNum2 = $fNum * 0.5; + $y = ($fNum2 * $fNum2); + $fRet = log($fNum2) * self::BESSELI($fNum, 1) + + (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y * + (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum; + } else { + $y = 2 / $fNum; + $fRet = exp(-$fNum) / sqrt($fNum) * + (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y * + (0.325614e-2 + $y * (-0.68245e-3))))))); + } + return $fRet; + } // function _Besselk1() + + + /** + * BESSELK + * + * Returns the modified Bessel function, which is equivalent to the Bessel functions evaluated for purely imaginary arguments. + * + * @param float $x + * @param float $ord + * @return float + */ + public static function BESSELK($x, $ord) { + $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x); + $ord = (is_null($ord)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($ord); + + if ((is_numeric($x)) && (is_numeric($ord))) { + if (($ord < 0) || ($x == 0.0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + + switch(floor($ord)) { + case 0 : return self::_Besselk0($x); + break; + case 1 : return self::_Besselk1($x); + break; + default : $fTox = 2 / $x; + $fBkm = self::_Besselk0($x); + $fBk = self::_Besselk1($x); + for ($n = 1; $n < $ord; ++$n) { + $fBkp = $fBkm + $n * $fTox * $fBk; + $fBkm = $fBk; + $fBk = $fBkp; + } + } + return $fBk; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function BESSELK() + + + private static function _Bessely0($fNum) { + if ($fNum < 8.0) { + $y = ($fNum * $fNum); + $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733)))); + $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y)))); + $fRet = $f1 / $f2 + M_2DIVPI * self::BESSELJ($fNum, 0) * log($fNum); + } else { + $z = 8.0 / $fNum; + $y = ($z * $z); + $xx = $fNum - 0.785398164; + $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6))); + $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7)))); + $fRet = sqrt(M_2DIVPI / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2); + } + return $fRet; + } // function _Bessely0() + + + private static function _Bessely1($fNum) { + if ($fNum < 8.0) { + $y = ($fNum * $fNum); + $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y * + (-0.4237922726e7 + $y * 0.8511937935e4))))); + $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y * + (0.1020426050e6 + $y * (0.3549632885e3 + $y))))); + $fRet = $f1 / $f2 + M_2DIVPI * ( self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum); + } else { + $z = 8.0 / $fNum; + $y = ($z * $z); + $xx = $fNum - 2.356194491; + $f1 = 1 + $y * (0.183105e-2 + $y * (-0.3516396496e-4 + $y * (0.2457520174e-5 + $y * (-0.240337019e6)))); + $f2 = 0.04687499995 + $y * (-0.2002690873e-3 + $y * (0.8449199096e-5 + $y * (-0.88228987e-6 + $y * 0.105787412e-6))); + $fRet = sqrt(M_2DIVPI / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2); + #i12430# ...but this seems to work much better. +// $fRet = sqrt(M_2DIVPI / $fNum) * sin($fNum - 2.356194491); + } + return $fRet; + } // function _Bessely1() + + + /** + * BESSELY + * + * Returns the Bessel function, which is also called the Weber function or the Neumann function. + * + * @param float $x + * @param float $n + * @return int + */ + public static function BESSELY($x, $ord) { + $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x); + $ord = (is_null($ord)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($ord); + + if ((is_numeric($x)) && (is_numeric($ord))) { + if (($ord < 0) || ($x == 0.0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + + switch(floor($ord)) { + case 0 : return self::_Bessely0($x); + break; + case 1 : return self::_Bessely1($x); + break; + default: $fTox = 2 / $x; + $fBym = self::_Bessely0($x); + $fBy = self::_Bessely1($x); + for ($n = 1; $n < $ord; ++$n) { + $fByp = $n * $fTox * $fBy - $fBym; + $fBym = $fBy; + $fBy = $fByp; + } + } + return $fBy; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function BESSELY() + + + /** + * BINTODEC + * + * Return a binary value as Decimal. + * + * @param string $x + * @return string + */ + public static function BINTODEC($x) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + + if (is_bool($x)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $x = (int) $x; + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $x = floor($x); + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[01]/',$x,$out)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (strlen($x) > 10) { + return PHPExcel_Calculation_Functions::NaN(); + } elseif (strlen($x) == 10) { + // Two's Complement + $x = substr($x,-9); + return '-'.(512-bindec($x)); + } + return bindec($x); + } // function BINTODEC() + + + /** + * BINTOHEX + * + * Return a binary value as Hex. + * + * @param string $x + * @return string + */ + public static function BINTOHEX($x, $places=null) { + $x = floor(PHPExcel_Calculation_Functions::flattenSingleValue($x)); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $x = (int) $x; + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $x = floor($x); + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[01]/',$x,$out)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (strlen($x) > 10) { + return PHPExcel_Calculation_Functions::NaN(); + } elseif (strlen($x) == 10) { + // Two's Complement + return str_repeat('F',8).substr(strtoupper(dechex(bindec(substr($x,-9)))),-2); + } + $hexVal = (string) strtoupper(dechex(bindec($x))); + + return self::_nbrConversionFormat($hexVal,$places); + } // function BINTOHEX() + + + /** + * BINTOOCT + * + * Return a binary value as Octal. + * + * @param string $x + * @return string + */ + public static function BINTOOCT($x, $places=null) { + $x = floor(PHPExcel_Calculation_Functions::flattenSingleValue($x)); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $x = (int) $x; + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $x = floor($x); + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[01]/',$x,$out)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (strlen($x) > 10) { + return PHPExcel_Calculation_Functions::NaN(); + } elseif (strlen($x) == 10) { + // Two's Complement + return str_repeat('7',7).substr(strtoupper(decoct(bindec(substr($x,-9)))),-3); + } + $octVal = (string) decoct(bindec($x)); + + return self::_nbrConversionFormat($octVal,$places); + } // function BINTOOCT() + + + /** + * DECTOBIN + * + * Return an octal value as binary. + * + * @param string $x + * @return string + */ + public static function DECTOBIN($x, $places=null) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $x = (int) $x; + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) floor($x); + $r = decbin($x); + if (strlen($r) == 32) { + // Two's Complement + $r = substr($r,-10); + } elseif (strlen($r) > 11) { + return PHPExcel_Calculation_Functions::NaN(); + } + + return self::_nbrConversionFormat($r,$places); + } // function DECTOBIN() + + + /** + * DECTOHEX + * + * Return an octal value as binary. + * + * @param string $x + * @return string + */ + public static function DECTOHEX($x, $places=null) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $x = (int) $x; + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) floor($x); + $r = strtoupper(dechex($x)); + if (strlen($r) == 8) { + // Two's Complement + $r = 'FF'.$r; + } + + return self::_nbrConversionFormat($r,$places); + } // function DECTOHEX() + + + /** + * DECTOOCT + * + * Return an octal value as binary. + * + * @param string $x + * @return string + */ + public static function DECTOOCT($x, $places=null) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $x = (int) $x; + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) floor($x); + $r = decoct($x); + if (strlen($r) == 11) { + // Two's Complement + $r = substr($r,-10); + } + + return self::_nbrConversionFormat($r,$places); + } // function DECTOOCT() + + + /** + * HEXTOBIN + * + * Return a hex value as binary. + * + * @param string $x + * @return string + */ + public static function HEXTOBIN($x, $places=null) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $binVal = decbin(hexdec($x)); + + return substr(self::_nbrConversionFormat($binVal,$places),-10); + } // function HEXTOBIN() + + + /** + * HEXTODEC + * + * Return a hex value as octal. + * + * @param string $x + * @return string + */ + public static function HEXTODEC($x) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + + if (is_bool($x)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return hexdec($x); + } // function HEXTODEC() + + + /** + * HEXTOOCT + * + * Return a hex value as octal. + * + * @param string $x + * @return string + */ + public static function HEXTOOCT($x, $places=null) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) $x; + if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $octVal = decoct(hexdec($x)); + + return self::_nbrConversionFormat($octVal,$places); + } // function HEXTOOCT() + + + /** + * OCTTOBIN + * + * Return an octal value as binary. + * + * @param string $x + * @return string + */ + public static function OCTTOBIN($x, $places=null) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) $x; + if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $r = decbin(octdec($x)); + + return self::_nbrConversionFormat($r,$places); + } // function OCTTOBIN() + + + /** + * OCTTODEC + * + * Return an octal value as binary. + * + * @param string $x + * @return string + */ + public static function OCTTODEC($x) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + + if (is_bool($x)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) $x; + if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return octdec($x); + } // function OCTTODEC() + + + /** + * OCTTOHEX + * + * Return an octal value as hex. + * + * @param string $x + * @return string + */ + public static function OCTTOHEX($x, $places=null) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $places = PHPExcel_Calculation_Functions::flattenSingleValue($places); + + if (is_bool($x)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $x = (string) $x; + if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $hexVal = strtoupper(dechex(octdec($x))); + + return self::_nbrConversionFormat($hexVal,$places); + } // function OCTTOHEX() + + + /** + * COMPLEX + * + * returns a complex number of the form x + yi or x + yj. + * + * @param float $realNumber + * @param float $imaginary + * @param string $suffix + * @return string + */ + public static function COMPLEX($realNumber=0.0, $imaginary=0.0, $suffix='i') { + $realNumber = (is_null($realNumber)) ? 0.0 : (float) PHPExcel_Calculation_Functions::flattenSingleValue($realNumber); + $imaginary = (is_null($imaginary)) ? 0.0 : (float) PHPExcel_Calculation_Functions::flattenSingleValue($imaginary); + $suffix = (is_null($suffix)) ? 'i' : PHPExcel_Calculation_Functions::flattenSingleValue($suffix); + + if (((is_numeric($realNumber)) && (is_numeric($imaginary))) && + (($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))) { + if ($suffix == '') $suffix = 'i'; + if ($realNumber == 0.0) { + if ($imaginary == 0.0) { + return (string) '0'; + } elseif ($imaginary == 1.0) { + return (string) $suffix; + } elseif ($imaginary == -1.0) { + return (string) '-'.$suffix; + } + return (string) $imaginary.$suffix; + } elseif ($imaginary == 0.0) { + return (string) $realNumber; + } elseif ($imaginary == 1.0) { + return (string) $realNumber.'+'.$suffix; + } elseif ($imaginary == -1.0) { + return (string) $realNumber.'-'.$suffix; + } + if ($imaginary > 0) { $imaginary = (string) '+'.$imaginary; } + return (string) $realNumber.$imaginary.$suffix; + } + + return PHPExcel_Calculation_Functions::VALUE(); + } // function COMPLEX() + + + /** + * IMAGINARY + * + * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return real + */ + public static function IMAGINARY($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + return $parsedComplex['imaginary']; + } // function IMAGINARY() + + + /** + * IMREAL + * + * Returns the real coefficient of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return real + */ + public static function IMREAL($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + return $parsedComplex['real']; + } // function IMREAL() + + + /** + * IMABS + * + * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return real + */ + public static function IMABS($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + return sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])); + } // function IMABS() + + + /** + * IMARGUMENT + * + * Returns the argument theta of a complex number, i.e. the angle in radians from the real axis to the representation of the number in polar coordinates. + * + * @param string $complexNumber + * @return string + */ + public static function IMARGUMENT($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if ($parsedComplex['real'] == 0.0) { + if ($parsedComplex['imaginary'] == 0.0) { + return 0.0; + } elseif($parsedComplex['imaginary'] < 0.0) { + return M_PI / -2; + } else { + return M_PI / 2; + } + } elseif ($parsedComplex['real'] > 0.0) { + return atan($parsedComplex['imaginary'] / $parsedComplex['real']); + } elseif ($parsedComplex['imaginary'] < 0.0) { + return 0 - (M_PI - atan(abs($parsedComplex['imaginary']) / abs($parsedComplex['real']))); + } else { + return M_PI - atan($parsedComplex['imaginary'] / abs($parsedComplex['real'])); + } + } // function IMARGUMENT() + + + /** + * IMCONJUGATE + * + * Returns the complex conjugate of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMCONJUGATE($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if ($parsedComplex['imaginary'] == 0.0) { + return $parsedComplex['real']; + } else { + return self::_cleanComplex(self::COMPLEX($parsedComplex['real'], 0 - $parsedComplex['imaginary'], $parsedComplex['suffix'])); + } + } // function IMCONJUGATE() + + + /** + * IMCOS + * + * Returns the cosine of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMCOS($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if ($parsedComplex['imaginary'] == 0.0) { + return cos($parsedComplex['real']); + } else { + return self::IMCONJUGATE(self::COMPLEX(cos($parsedComplex['real']) * cosh($parsedComplex['imaginary']),sin($parsedComplex['real']) * sinh($parsedComplex['imaginary']),$parsedComplex['suffix'])); + } + } // function IMCOS() + + + /** + * IMSIN + * + * Returns the sine of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMSIN($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if ($parsedComplex['imaginary'] == 0.0) { + return sin($parsedComplex['real']); + } else { + return self::COMPLEX(sin($parsedComplex['real']) * cosh($parsedComplex['imaginary']),cos($parsedComplex['real']) * sinh($parsedComplex['imaginary']),$parsedComplex['suffix']); + } + } // function IMSIN() + + + /** + * IMSQRT + * + * Returns the square root of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMSQRT($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + $theta = self::IMARGUMENT($complexNumber); + $d1 = cos($theta / 2); + $d2 = sin($theta / 2); + $r = sqrt(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']))); + + if ($parsedComplex['suffix'] == '') { + return self::COMPLEX($d1 * $r,$d2 * $r); + } else { + return self::COMPLEX($d1 * $r,$d2 * $r,$parsedComplex['suffix']); + } + } // function IMSQRT() + + + /** + * IMLN + * + * Returns the natural logarithm of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMLN($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $logR = log(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']))); + $t = self::IMARGUMENT($complexNumber); + + if ($parsedComplex['suffix'] == '') { + return self::COMPLEX($logR,$t); + } else { + return self::COMPLEX($logR,$t,$parsedComplex['suffix']); + } + } // function IMLN() + + + /** + * IMLOG10 + * + * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMLOG10($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { + return PHPExcel_Calculation_Functions::NaN(); + } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) { + return log10($parsedComplex['real']); + } + + return self::IMPRODUCT(log10(EULER),self::IMLN($complexNumber)); + } // function IMLOG10() + + + /** + * IMLOG2 + * + * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMLOG2($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { + return PHPExcel_Calculation_Functions::NaN(); + } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) { + return log($parsedComplex['real'],2); + } + + return self::IMPRODUCT(log(EULER,2),self::IMLN($complexNumber)); + } // function IMLOG2() + + + /** + * IMEXP + * + * Returns the exponential of a complex number in x + yi or x + yj text format. + * + * @param string $complexNumber + * @return string + */ + public static function IMEXP($complexNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { + return '1'; + } + + $e = exp($parsedComplex['real']); + $eX = $e * cos($parsedComplex['imaginary']); + $eY = $e * sin($parsedComplex['imaginary']); + + if ($parsedComplex['suffix'] == '') { + return self::COMPLEX($eX,$eY); + } else { + return self::COMPLEX($eX,$eY,$parsedComplex['suffix']); + } + } // function IMEXP() + + + /** + * IMPOWER + * + * Returns a complex number in x + yi or x + yj text format raised to a power. + * + * @param string $complexNumber + * @return string + */ + public static function IMPOWER($complexNumber,$realNumber) { + $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber); + $realNumber = PHPExcel_Calculation_Functions::flattenSingleValue($realNumber); + + if (!is_numeric($realNumber)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + $parsedComplex = self::_parseComplex($complexNumber); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + $r = sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])); + $rPower = pow($r,$realNumber); + $theta = self::IMARGUMENT($complexNumber) * $realNumber; + if ($theta == 0) { + return 1; + } elseif ($parsedComplex['imaginary'] == 0.0) { + return self::COMPLEX($rPower * cos($theta),$rPower * sin($theta),$parsedComplex['suffix']); + } else { + return self::COMPLEX($rPower * cos($theta),$rPower * sin($theta),$parsedComplex['suffix']); + } + } // function IMPOWER() + + + /** + * IMDIV + * + * Returns the quotient of two complex numbers in x + yi or x + yj text format. + * + * @param string $complexDividend + * @param string $complexDivisor + * @return real + */ + public static function IMDIV($complexDividend,$complexDivisor) { + $complexDividend = PHPExcel_Calculation_Functions::flattenSingleValue($complexDividend); + $complexDivisor = PHPExcel_Calculation_Functions::flattenSingleValue($complexDivisor); + + $parsedComplexDividend = self::_parseComplex($complexDividend); + if (!is_array($parsedComplexDividend)) { + return $parsedComplexDividend; + } + + $parsedComplexDivisor = self::_parseComplex($complexDivisor); + if (!is_array($parsedComplexDivisor)) { + return $parsedComplexDividend; + } + + if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] != '') && + ($parsedComplexDividend['suffix'] != $parsedComplexDivisor['suffix'])) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] == '')) { + $parsedComplexDivisor['suffix'] = $parsedComplexDividend['suffix']; + } + + $d1 = ($parsedComplexDividend['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['imaginary']); + $d2 = ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['real']) - ($parsedComplexDividend['real'] * $parsedComplexDivisor['imaginary']); + $d3 = ($parsedComplexDivisor['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDivisor['imaginary'] * $parsedComplexDivisor['imaginary']); + + $r = $d1/$d3; + $i = $d2/$d3; + + if ($i > 0.0) { + return self::_cleanComplex($r.'+'.$i.$parsedComplexDivisor['suffix']); + } elseif ($i < 0.0) { + return self::_cleanComplex($r.$i.$parsedComplexDivisor['suffix']); + } else { + return $r; + } + } // function IMDIV() + + + /** + * IMSUB + * + * Returns the difference of two complex numbers in x + yi or x + yj text format. + * + * @param string $complexNumber1 + * @param string $complexNumber2 + * @return real + */ + public static function IMSUB($complexNumber1,$complexNumber2) { + $complexNumber1 = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber1); + $complexNumber2 = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber2); + + $parsedComplex1 = self::_parseComplex($complexNumber1); + if (!is_array($parsedComplex1)) { + return $parsedComplex1; + } + + $parsedComplex2 = self::_parseComplex($complexNumber2); + if (!is_array($parsedComplex2)) { + return $parsedComplex2; + } + + if ((($parsedComplex1['suffix'] != '') && ($parsedComplex2['suffix'] != '')) && + ($parsedComplex1['suffix'] != $parsedComplex2['suffix'])) { + return PHPExcel_Calculation_Functions::NaN(); + } elseif (($parsedComplex1['suffix'] == '') && ($parsedComplex2['suffix'] != '')) { + $parsedComplex1['suffix'] = $parsedComplex2['suffix']; + } + + $d1 = $parsedComplex1['real'] - $parsedComplex2['real']; + $d2 = $parsedComplex1['imaginary'] - $parsedComplex2['imaginary']; + + return self::COMPLEX($d1,$d2,$parsedComplex1['suffix']); + } // function IMSUB() + + + /** + * IMSUM + * + * Returns the sum of two or more complex numbers in x + yi or x + yj text format. + * + * @param array of mixed Data Series + * @return real + */ + public static function IMSUM() { + // Return value + $returnValue = self::_parseComplex('0'); + $activeSuffix = ''; + + // Loop through the arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + $parsedComplex = self::_parseComplex($arg); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + + if ($activeSuffix == '') { + $activeSuffix = $parsedComplex['suffix']; + } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + $returnValue['real'] += $parsedComplex['real']; + $returnValue['imaginary'] += $parsedComplex['imaginary']; + } + + if ($returnValue['imaginary'] == 0.0) { $activeSuffix = ''; } + return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix); + } // function IMSUM() + + + /** + * IMPRODUCT + * + * Returns the product of two or more complex numbers in x + yi or x + yj text format. + * + * @param array of mixed Data Series + * @return real + */ + public static function IMPRODUCT() { + // Return value + $returnValue = self::_parseComplex('1'); + $activeSuffix = ''; + + // Loop through the arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + $parsedComplex = self::_parseComplex($arg); + if (!is_array($parsedComplex)) { + return $parsedComplex; + } + $workValue = $returnValue; + if (($parsedComplex['suffix'] != '') && ($activeSuffix == '')) { + $activeSuffix = $parsedComplex['suffix']; + } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) { + return PHPExcel_Calculation_Functions::NaN(); + } + $returnValue['real'] = ($workValue['real'] * $parsedComplex['real']) - ($workValue['imaginary'] * $parsedComplex['imaginary']); + $returnValue['imaginary'] = ($workValue['real'] * $parsedComplex['imaginary']) + ($workValue['imaginary'] * $parsedComplex['real']); + } + + if ($returnValue['imaginary'] == 0.0) { $activeSuffix = ''; } + return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix); + } // function IMPRODUCT() + + + /** + * DELTA + * + * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise. + * + * @param float $a + * @param float $b + * @return int + */ + public static function DELTA($a, $b=0) { + $a = PHPExcel_Calculation_Functions::flattenSingleValue($a); + $b = PHPExcel_Calculation_Functions::flattenSingleValue($b); + + return (int) ($a == $b); + } // function DELTA() + + + /** + * GESTEP + * + * Returns 1 if number = step; returns 0 (zero) otherwise + * + * @param float $number + * @param float $step + * @return int + */ + public static function GESTEP($number, $step=0) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + $step = PHPExcel_Calculation_Functions::flattenSingleValue($step); + + return (int) ($number >= $step); + } // function GESTEP() + + + // + // Private method to calculate the erf value + // + private static $_two_sqrtpi = 1.128379167095512574; + + public static function _erfVal($x) { + if (abs($x) > 2.2) { + return 1 - self::_erfcVal($x); + } + $sum = $term = $x; + $xsqr = ($x * $x); + $j = 1; + do { + $term *= $xsqr / $j; + $sum -= $term / (2 * $j + 1); + ++$j; + $term *= $xsqr / $j; + $sum += $term / (2 * $j + 1); + ++$j; + if ($sum == 0.0) { + break; + } + } while (abs($term / $sum) > PRECISION); + return self::$_two_sqrtpi * $sum; + } // function _erfVal() + + + /** + * ERF + * + * Returns the error function integrated between lower_limit and upper_limit + * + * @param float $lower lower bound for integrating ERF + * @param float $upper upper bound for integrating ERF. + * If omitted, ERF integrates between zero and lower_limit + * @return int + */ + public static function ERF($lower, $upper = null) { + $lower = PHPExcel_Calculation_Functions::flattenSingleValue($lower); + $upper = PHPExcel_Calculation_Functions::flattenSingleValue($upper); + + if (is_numeric($lower)) { + if ($lower < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (is_null($upper)) { + return self::_erfVal($lower); + } + if (is_numeric($upper)) { + if ($upper < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return self::_erfVal($upper) - self::_erfVal($lower); + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function ERF() + + + // + // Private method to calculate the erfc value + // + private static $_one_sqrtpi = 0.564189583547756287; + + private static function _erfcVal($x) { + if (abs($x) < 2.2) { + return 1 - self::_erfVal($x); + } + if ($x < 0) { + return 2 - self::ERFC(-$x); + } + $a = $n = 1; + $b = $c = $x; + $d = ($x * $x) + 0.5; + $q1 = $q2 = $b / $d; + $t = 0; + do { + $t = $a * $n + $b * $x; + $a = $b; + $b = $t; + $t = $c * $n + $d * $x; + $c = $d; + $d = $t; + $n += 0.5; + $q1 = $q2; + $q2 = $b / $d; + } while ((abs($q1 - $q2) / $q2) > PRECISION); + return self::$_one_sqrtpi * exp(-$x * $x) * $q2; + } // function _erfcVal() + + + /** + * ERFC + * + * Returns the complementary ERF function integrated between x and infinity + * + * @param float $x The lower bound for integrating ERF + * @return int + */ + public static function ERFC($x) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + + if (is_numeric($x)) { + if ($x < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return self::_erfcVal($x); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function ERFC() + + + /** + * getConversionGroups + * + * @return array + */ + public static function getConversionGroups() { + $conversionGroups = array(); + foreach(self::$_conversionUnits as $conversionUnit) { + $conversionGroups[] = $conversionUnit['Group']; + } + return array_merge(array_unique($conversionGroups)); + } // function getConversionGroups() + + + /** + * getConversionGroupUnits + * + * @return array + */ + public static function getConversionGroupUnits($group = NULL) { + $conversionGroups = array(); + foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup) { + if ((is_null($group)) || ($conversionGroup['Group'] == $group)) { + $conversionGroups[$conversionGroup['Group']][] = $conversionUnit; + } + } + return $conversionGroups; + } // function getConversionGroupUnits() + + + /** + * getConversionGroupUnitDetails + * + * @return array + */ + public static function getConversionGroupUnitDetails($group = NULL) { + $conversionGroups = array(); + foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup) { + if ((is_null($group)) || ($conversionGroup['Group'] == $group)) { + $conversionGroups[$conversionGroup['Group']][] = array( 'unit' => $conversionUnit, + 'description' => $conversionGroup['Unit Name'] + ); + } + } + return $conversionGroups; + } // function getConversionGroupUnitDetails() + + + /** + * getConversionGroups + * + * @return array + */ + public static function getConversionMultipliers() { + return self::$_conversionMultipliers; + } // function getConversionGroups() + + + /** + * CONVERTUOM + * + * @param float $value + * @param string $fromUOM + * @param string $toUOM + * @return float + */ + public static function CONVERTUOM($value, $fromUOM, $toUOM) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $fromUOM = PHPExcel_Calculation_Functions::flattenSingleValue($fromUOM); + $toUOM = PHPExcel_Calculation_Functions::flattenSingleValue($toUOM); + + if (!is_numeric($value)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $fromMultiplier = 1; + if (isset(self::$_conversionUnits[$fromUOM])) { + $unitGroup1 = self::$_conversionUnits[$fromUOM]['Group']; + } else { + $fromMultiplier = substr($fromUOM,0,1); + $fromUOM = substr($fromUOM,1); + if (isset(self::$_conversionMultipliers[$fromMultiplier])) { + $fromMultiplier = self::$_conversionMultipliers[$fromMultiplier]['multiplier']; + } else { + return PHPExcel_Calculation_Functions::NA(); + } + if ((isset(self::$_conversionUnits[$fromUOM])) && (self::$_conversionUnits[$fromUOM]['AllowPrefix'])) { + $unitGroup1 = self::$_conversionUnits[$fromUOM]['Group']; + } else { + return PHPExcel_Calculation_Functions::NA(); + } + } + $value *= $fromMultiplier; + + $toMultiplier = 1; + if (isset(self::$_conversionUnits[$toUOM])) { + $unitGroup2 = self::$_conversionUnits[$toUOM]['Group']; + } else { + $toMultiplier = substr($toUOM,0,1); + $toUOM = substr($toUOM,1); + if (isset(self::$_conversionMultipliers[$toMultiplier])) { + $toMultiplier = self::$_conversionMultipliers[$toMultiplier]['multiplier']; + } else { + return PHPExcel_Calculation_Functions::NA(); + } + if ((isset(self::$_conversionUnits[$toUOM])) && (self::$_conversionUnits[$toUOM]['AllowPrefix'])) { + $unitGroup2 = self::$_conversionUnits[$toUOM]['Group']; + } else { + return PHPExcel_Calculation_Functions::NA(); + } + } + if ($unitGroup1 != $unitGroup2) { + return PHPExcel_Calculation_Functions::NA(); + } + + if ($fromUOM == $toUOM) { + return 1.0; + } elseif ($unitGroup1 == 'Temperature') { + if (($fromUOM == 'F') || ($fromUOM == 'fah')) { + if (($toUOM == 'F') || ($toUOM == 'fah')) { + return 1.0; + } else { + $value = (($value - 32) / 1.8); + if (($toUOM == 'K') || ($toUOM == 'kel')) { + $value += 273.15; + } + return $value; + } + } elseif ((($fromUOM == 'K') || ($fromUOM == 'kel')) && + (($toUOM == 'K') || ($toUOM == 'kel'))) { + return 1.0; + } elseif ((($fromUOM == 'C') || ($fromUOM == 'cel')) && + (($toUOM == 'C') || ($toUOM == 'cel'))) { + return 1.0; + } + if (($toUOM == 'F') || ($toUOM == 'fah')) { + if (($fromUOM == 'K') || ($fromUOM == 'kel')) { + $value -= 273.15; + } + return ($value * 1.8) + 32; + } + if (($toUOM == 'C') || ($toUOM == 'cel')) { + return $value - 273.15; + } + return $value + 273.15; + } + return ($value * self::$_unitConversions[$unitGroup1][$fromUOM][$toUOM]) / $toMultiplier; + } // function CONVERTUOM() + +} // class PHPExcel_Calculation_Engineering diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Exception.php b/libraries/PHPExcel/PHPExcel/Calculation/Exception.php index b94f3f498..6c09d5a16 100644 --- a/libraries/PHPExcel/PHPExcel/Calculation/Exception.php +++ b/libraries/PHPExcel/PHPExcel/Calculation/Exception.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Calculation_Exception extends Exception { /** diff --git a/libraries/PHPExcel/PHPExcel/Calculation/ExceptionHandler.php b/libraries/PHPExcel/PHPExcel/Calculation/ExceptionHandler.php index 7050260eb..cc0caa8a2 100644 --- a/libraries/PHPExcel/PHPExcel/Calculation/ExceptionHandler.php +++ b/libraries/PHPExcel/PHPExcel/Calculation/ExceptionHandler.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Calculation_ExceptionHandler { /** diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Financial.php b/libraries/PHPExcel/PHPExcel/Calculation/Financial.php new file mode 100644 index 000000000..bd82ae259 --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/Financial.php @@ -0,0 +1,1818 @@ +modify('+1 day'); + return ($date->format('d') == 1); + } // function _lastDayOfMonth() + + + private static function _firstDayOfMonth($testDate) { + $date = clone $testDate; + return ($date->format('d') == 1); + } // function _lastDayOfMonth() + + + private static function _coupFirstPeriodDate($settlement, $maturity, $frequency, $next) { + $months = 12 / $frequency; + + $result = PHPExcel_Shared_Date::ExcelToPHPObject($maturity); + $eom = self::_lastDayOfMonth($result); + + while ($settlement < PHPExcel_Shared_Date::PHPToExcel($result)) { + $result->modify('-'.$months.' months'); + } + if ($next) { + $result->modify('+'.$months.' months'); + } + + if ($eom) { + $result->modify('-1 day'); + } + + return PHPExcel_Shared_Date::PHPToExcel($result); + } // function _coupFirstPeriodDate() + + + private static function _validFrequency($frequency) { + if (($frequency == 1) || ($frequency == 2) || ($frequency == 4)) { + return true; + } + if ((PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) && + (($frequency == 6) || ($frequency == 12))) { + return true; + } + return false; + } // function _validFrequency() + + + private static function _daysPerYear($year,$basis) { + switch ($basis) { + case 0 : + case 2 : + case 4 : + $daysPerYear = 360; + break; + case 3 : + $daysPerYear = 365; + break; + case 1 : + if (PHPExcel_Calculation_DateTime::_isLeapYear($year)) { + $daysPerYear = 366; + } else { + $daysPerYear = 365; + } + break; + default : + return PHPExcel_Calculation_Functions::NaN(); + } + return $daysPerYear; + } // function _daysPerYear() + + + private static function _interestAndPrincipal($rate=0, $per=0, $nper=0, $pv=0, $fv=0, $type=0) { + $pmt = self::PMT($rate, $nper, $pv, $fv, $type); + $capital = $pv; + for ($i = 1; $i<= $per; ++$i) { + $interest = ($type && $i == 1) ? 0 : -$capital * $rate; + $principal = $pmt - $interest; + $capital += $principal; + } + return array($interest, $principal); + } // function _interestAndPrincipal() + + + /** + * ACCRINT + * + * Returns the discount rate for a security. + * + * @param mixed issue The security's issue date. + * @param mixed firstinter The security's first interest date. + * @param mixed settlement The security's settlement date. + * @param float rate The security's annual coupon rate. + * @param float par The security's par value. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function ACCRINT($issue, $firstinter, $settlement, $rate, $par=1000, $frequency=1, $basis=0) { + $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue); + $firstinter = PHPExcel_Calculation_Functions::flattenSingleValue($firstinter); + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $rate = (float) PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $par = (is_null($par)) ? 1000 : (float) PHPExcel_Calculation_Functions::flattenSingleValue($par); + $frequency = (is_null($frequency)) ? 1 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if ((is_numeric($rate)) && (is_numeric($par))) { + if (($rate <= 0) || ($par <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + + return $par * $rate * $daysBetweenIssueAndSettlement; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function ACCRINT() + + + /** + * ACCRINTM + * + * Returns the discount rate for a security. + * + * @param mixed issue The security's issue date. + * @param mixed settlement The security's settlement date. + * @param float rate The security's annual coupon rate. + * @param float par The security's par value. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function ACCRINTM($issue, $settlement, $rate, $par=1000, $basis=0) { + $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue); + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $rate = (float) PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $par = (is_null($par)) ? 1000 : (float) PHPExcel_Calculation_Functions::flattenSingleValue($par); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if ((is_numeric($rate)) && (is_numeric($par))) { + if (($rate <= 0) || ($par <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + return $par * $rate * $daysBetweenIssueAndSettlement; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function ACCRINTM() + + + public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) { + $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost); + $purchased = PHPExcel_Calculation_Functions::flattenSingleValue($purchased); + $firstPeriod = PHPExcel_Calculation_Functions::flattenSingleValue($firstPeriod); + $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage); + $period = floor(PHPExcel_Calculation_Functions::flattenSingleValue($period)); + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + $fUsePer = 1.0 / $rate; + + if ($fUsePer < 3.0) { + $amortiseCoeff = 1.0; + } elseif ($fUsePer < 5.0) { + $amortiseCoeff = 1.5; + } elseif ($fUsePer <= 6.0) { + $amortiseCoeff = 2.0; + } else { + $amortiseCoeff = 2.5; + } + + $rate *= $amortiseCoeff; + $fNRate = round(PHPExcel_Calculation_DateTime::YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost,0); + $cost -= $fNRate; + $fRest = $cost - $salvage; + + for ($n = 0; $n < $period; ++$n) { + $fNRate = round($rate * $cost,0); + $fRest -= $fNRate; + + if ($fRest < 0.0) { + switch ($period - $n) { + case 0 : + case 1 : return round($cost * 0.5,0); + break; + default : return 0.0; + break; + } + } + $cost -= $fNRate; + } + return $fNRate; + } // function AMORDEGRC() + + + public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) { + $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost); + $purchased = PHPExcel_Calculation_Functions::flattenSingleValue($purchased); + $firstPeriod = PHPExcel_Calculation_Functions::flattenSingleValue($firstPeriod); + $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage); + $period = PHPExcel_Calculation_Functions::flattenSingleValue($period); + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + $fOneRate = $cost * $rate; + $fCostDelta = $cost - $salvage; + // Note, quirky variation for leap years on the YEARFRAC for this function + $purchasedYear = PHPExcel_Calculation_DateTime::YEAR($purchased); + $yearFrac = PHPExcel_Calculation_DateTime::YEARFRAC($purchased, $firstPeriod, $basis); + + if (($basis == 1) && ($yearFrac < 1) && (PHPExcel_Calculation_DateTime::_isLeapYear($purchasedYear))) { + $yearFrac *= 365 / 366; + } + + $f0Rate = $yearFrac * $rate * $cost; + $nNumOfFullPeriods = intval(($cost - $salvage - $f0Rate) / $fOneRate); + + if ($period == 0) { + return $f0Rate; + } elseif ($period <= $nNumOfFullPeriods) { + return $fOneRate; + } elseif ($period == ($nNumOfFullPeriods + 1)) { + return ($fCostDelta - $fOneRate * $nNumOfFullPeriods - $f0Rate); + } else { + return 0.0; + } + } // function AMORLINC() + + + public static function COUPDAYBS($settlement, $maturity, $frequency, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (($settlement > $maturity) || + (!self::_validFrequency($frequency)) || + (($basis < 0) || ($basis > 4))) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis); + $prev = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False); + + return PHPExcel_Calculation_DateTime::YEARFRAC($prev, $settlement, $basis) * $daysPerYear; + } // function COUPDAYBS() + + + public static function COUPDAYS($settlement, $maturity, $frequency, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (($settlement > $maturity) || + (!self::_validFrequency($frequency)) || + (($basis < 0) || ($basis > 4))) { + return PHPExcel_Calculation_Functions::NaN(); + } + + switch ($basis) { + case 3: // Actual/365 + return 365 / $frequency; + case 1: // Actual/actual + if ($frequency == 1) { + $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($maturity),$basis); + return ($daysPerYear / $frequency); + } else { + $prev = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False); + $next = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); + return ($next - $prev); + } + default: // US (NASD) 30/360, Actual/360 or European 30/360 + return 360 / $frequency; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function COUPDAYS() + + + public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (($settlement > $maturity) || + (!self::_validFrequency($frequency)) || + (($basis < 0) || ($basis > 4))) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis); + $next = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); + + return PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $next, $basis) * $daysPerYear; + } // function COUPDAYSNC() + + + public static function COUPNCD($settlement, $maturity, $frequency, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (($settlement > $maturity) || + (!self::_validFrequency($frequency)) || + (($basis < 0) || ($basis > 4))) { + return PHPExcel_Calculation_Functions::NaN(); + } + + return self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); + } // function COUPNCD() + + + public static function COUPNUM($settlement, $maturity, $frequency, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (($settlement > $maturity) || + (!self::_validFrequency($frequency)) || + (($basis < 0) || ($basis > 4))) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $settlement = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis) * 365; + + switch ($frequency) { + case 1: // annual payments + return ceil($daysBetweenSettlementAndMaturity / 360); + case 2: // half-yearly + return ceil($daysBetweenSettlementAndMaturity / 180); + case 4: // quarterly + return ceil($daysBetweenSettlementAndMaturity / 90); + case 6: // bimonthly + return ceil($daysBetweenSettlementAndMaturity / 60); + case 12: // monthly + return ceil($daysBetweenSettlementAndMaturity / 30); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function COUPNUM() + + + public static function COUPPCD($settlement, $maturity, $frequency, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (($settlement > $maturity) || + (!self::_validFrequency($frequency)) || + (($basis < 0) || ($basis > 4))) { + return PHPExcel_Calculation_Functions::NaN(); + } + + return self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False); + } // function COUPPCD() + + + /** + * CUMIPMT + * + * Returns the cumulative interest paid on a loan between start_period and end_period. + * + * @param float $rate Interest rate per period + * @param int $nper Number of periods + * @param float $pv Present Value + * @param int start The first period in the calculation. + * Payment periods are numbered beginning with 1. + * @param int end The last period in the calculation. + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $start = (int) PHPExcel_Calculation_Functions::flattenSingleValue($start); + $end = (int) PHPExcel_Calculation_Functions::flattenSingleValue($end); + $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($start < 1 || $start > $end) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Calculate + $interest = 0; + for ($per = $start; $per <= $end; ++$per) { + $interest += self::IPMT($rate, $per, $nper, $pv, 0, $type); + } + + return $interest; + } // function CUMIPMT() + + + /** + * CUMPRINC + * + * Returns the cumulative principal paid on a loan between start_period and end_period. + * + * @param float $rate Interest rate per period + * @param int $nper Number of periods + * @param float $pv Present Value + * @param int start The first period in the calculation. + * Payment periods are numbered beginning with 1. + * @param int end The last period in the calculation. + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $start = (int) PHPExcel_Calculation_Functions::flattenSingleValue($start); + $end = (int) PHPExcel_Calculation_Functions::flattenSingleValue($end); + $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($start < 1 || $start > $end) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Calculate + $principal = 0; + for ($per = $start; $per <= $end; ++$per) { + $principal += self::PPMT($rate, $per, $nper, $pv, 0, $type); + } + + return $principal; + } // function CUMPRINC() + + + /** + * DB + * + * Returns the depreciation of an asset for a specified period using the fixed-declining balance method. + * This form of depreciation is used if you want to get a higher depreciation value at the beginning of the depreciation + * (as opposed to linear depreciation). The depreciation value is reduced with every depreciation period by the + * depreciation already deducted from the initial cost. + * + * @param float cost Initial cost of the asset. + * @param float salvage Value at the end of the depreciation. (Sometimes called the salvage value of the asset) + * @param int life Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset) + * @param int period The period for which you want to calculate the depreciation. Period must use the same units as life. + * @param float month Number of months in the first year. If month is omitted, it defaults to 12. + * @return float + */ + public static function DB($cost, $salvage, $life, $period, $month=12) { + $cost = (float) PHPExcel_Calculation_Functions::flattenSingleValue($cost); + $salvage = (float) PHPExcel_Calculation_Functions::flattenSingleValue($salvage); + $life = (int) PHPExcel_Calculation_Functions::flattenSingleValue($life); + $period = (int) PHPExcel_Calculation_Functions::flattenSingleValue($period); + $month = (int) PHPExcel_Calculation_Functions::flattenSingleValue($month); + + // Validate + if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) { + if ($cost == 0) { + return 0.0; + } elseif (($cost < 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($month < 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + // Set Fixed Depreciation Rate + $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life)); + $fixedDepreciationRate = round($fixedDepreciationRate, 3); + + // Loop through each period calculating the depreciation + $previousDepreciation = 0; + for ($per = 1; $per <= $period; ++$per) { + if ($per == 1) { + $depreciation = $cost * $fixedDepreciationRate * $month / 12; + } elseif ($per == ($life + 1)) { + $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12; + } else { + $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate; + } + $previousDepreciation += $depreciation; + } + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $depreciation = round($depreciation,2); + } + return $depreciation; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function DB() + + + /** + * DDB + * + * Returns the depreciation of an asset for a specified period using the double-declining balance method or some other method you specify. + * + * @param float cost Initial cost of the asset. + * @param float salvage Value at the end of the depreciation. (Sometimes called the salvage value of the asset) + * @param int life Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset) + * @param int period The period for which you want to calculate the depreciation. Period must use the same units as life. + * @param float factor The rate at which the balance declines. + * If factor is omitted, it is assumed to be 2 (the double-declining balance method). + * @return float + */ + public static function DDB($cost, $salvage, $life, $period, $factor=2.0) { + $cost = (float) PHPExcel_Calculation_Functions::flattenSingleValue($cost); + $salvage = (float) PHPExcel_Calculation_Functions::flattenSingleValue($salvage); + $life = (int) PHPExcel_Calculation_Functions::flattenSingleValue($life); + $period = (int) PHPExcel_Calculation_Functions::flattenSingleValue($period); + $factor = (float) PHPExcel_Calculation_Functions::flattenSingleValue($factor); + + // Validate + if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) { + if (($cost <= 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($factor <= 0.0) || ($period > $life)) { + return PHPExcel_Calculation_Functions::NaN(); + } + // Set Fixed Depreciation Rate + $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life)); + $fixedDepreciationRate = round($fixedDepreciationRate, 3); + + // Loop through each period calculating the depreciation + $previousDepreciation = 0; + for ($per = 1; $per <= $period; ++$per) { + $depreciation = min( ($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation) ); + $previousDepreciation += $depreciation; + } + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + $depreciation = round($depreciation,2); + } + return $depreciation; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function DDB() + + + /** + * DISC + * + * Returns the discount rate for a security. + * + * @param mixed settlement The security's settlement date. + * The security settlement date is the date after the issue date when the security is traded to the buyer. + * @param mixed maturity The security's maturity date. + * The maturity date is the date when the security expires. + * @param int price The security's price per $100 face value. + * @param int redemption the security's redemption value per $100 face value. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function DISC($settlement, $maturity, $price, $redemption, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $price = (float) PHPExcel_Calculation_Functions::flattenSingleValue($price); + $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption); + $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) { + if (($price <= 0) || ($redemption <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return ((1 - $price / $redemption) / $daysBetweenSettlementAndMaturity); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function DISC() + + + /** + * DOLLARDE + * + * Converts a dollar price expressed as an integer part and a fraction part into a dollar price expressed as a decimal number. + * Fractional dollar numbers are sometimes used for security prices. + * + * @param float $fractional_dollar Fractional Dollar + * @param int $fraction Fraction + * @return float + */ + public static function DOLLARDE($fractional_dollar = Null, $fraction = 0) { + $fractional_dollar = PHPExcel_Calculation_Functions::flattenSingleValue($fractional_dollar); + $fraction = (int)PHPExcel_Calculation_Functions::flattenSingleValue($fraction); + + // Validate parameters + if (is_null($fractional_dollar) || $fraction < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($fraction == 0) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $dollars = floor($fractional_dollar); + $cents = fmod($fractional_dollar,1); + $cents /= $fraction; + $cents *= pow(10,ceil(log10($fraction))); + return $dollars + $cents; + } // function DOLLARDE() + + + /** + * DOLLARFR + * + * Converts a dollar price expressed as a decimal number into a dollar price expressed as a fraction. + * Fractional dollar numbers are sometimes used for security prices. + * + * @param float $decimal_dollar Decimal Dollar + * @param int $fraction Fraction + * @return float + */ + public static function DOLLARFR($decimal_dollar = Null, $fraction = 0) { + $decimal_dollar = PHPExcel_Calculation_Functions::flattenSingleValue($decimal_dollar); + $fraction = (int)PHPExcel_Calculation_Functions::flattenSingleValue($fraction); + + // Validate parameters + if (is_null($decimal_dollar) || $fraction < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($fraction == 0) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $dollars = floor($decimal_dollar); + $cents = fmod($decimal_dollar,1); + $cents *= $fraction; + $cents *= pow(10,-ceil(log10($fraction))); + return $dollars + $cents; + } // function DOLLARFR() + + + /** + * EFFECT + * + * Returns the effective interest rate given the nominal rate and the number of compounding payments per year. + * + * @param float $nominal_rate Nominal interest rate + * @param int $npery Number of compounding payments per year + * @return float + */ + public static function EFFECT($nominal_rate = 0, $npery = 0) { + $nominal_rate = PHPExcel_Calculation_Functions::flattenSingleValue($nominal_rate); + $npery = (int)PHPExcel_Calculation_Functions::flattenSingleValue($npery); + + // Validate parameters + if ($nominal_rate <= 0 || $npery < 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + + return pow((1 + $nominal_rate / $npery), $npery) - 1; + } // function EFFECT() + + + /** + * FV + * + * Returns the Future Value of a cash flow with constant payments and interest rate (annuities). + * + * @param float $rate Interest rate per period + * @param int $nper Number of periods + * @param float $pmt Periodic payment (annuity) + * @param float $pv Present Value + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $type = PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Calculate + if (!is_null($rate) && $rate != 0) { + return -$pv * pow(1 + $rate, $nper) - $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate; + } else { + return -$pv - $pmt * $nper; + } + } // function FV() + + + /** + * FVSCHEDULE + * + */ + public static function FVSCHEDULE($principal, $schedule) { + $principal = PHPExcel_Calculation_Functions::flattenSingleValue($principal); + $schedule = PHPExcel_Calculation_Functions::flattenArray($schedule); + + foreach($schedule as $n) { + $principal *= 1 + $n; + } + + return $principal; + } // function FVSCHEDULE() + + + /** + * INTRATE + * + * Returns the interest rate for a fully invested security. + * + * @param mixed settlement The security's settlement date. + * The security settlement date is the date after the issue date when the security is traded to the buyer. + * @param mixed maturity The security's maturity date. + * The maturity date is the date when the security expires. + * @param int investment The amount invested in the security. + * @param int redemption The amount to be received at maturity. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $investment = (float) PHPExcel_Calculation_Functions::flattenSingleValue($investment); + $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption); + $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) { + if (($investment <= 0) || ($redemption <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function INTRATE() + + + /** + * IPMT + * + * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate. + * + * @param float $rate Interest rate per period + * @param int $per Period for which we want to find the interest + * @param int $nper Number of periods + * @param float $pv Present Value + * @param float $fv Future Value + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $per = (int) PHPExcel_Calculation_Functions::flattenSingleValue($per); + $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv); + $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($per <= 0 || $per > $nper) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Calculate + $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type); + return $interestAndPrincipal[0]; + } // function IPMT() + + + public static function IRR($values, $guess = 0.1) { + if (!is_array($values)) return PHPExcel_Calculation_Functions::VALUE(); + $values = PHPExcel_Calculation_Functions::flattenArray($values); + $guess = PHPExcel_Calculation_Functions::flattenSingleValue($guess); + + // create an initial range, with a root somewhere between 0 and guess + $x1 = 0.0; + $x2 = $guess; + $f1 = self::NPV($x1, $values); + $f2 = self::NPV($x2, $values); + for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { + if (($f1 * $f2) < 0.0) break; + if (abs($f1) < abs($f2)) { + $f1 = self::NPV($x1 += 1.6 * ($x1 - $x2), $values); + } else { + $f2 = self::NPV($x2 += 1.6 * ($x2 - $x1), $values); + } + } + if (($f1 * $f2) > 0.0) return PHPExcel_Calculation_Functions::VALUE(); + + $f = self::NPV($x1, $values); + if ($f < 0.0) { + $rtb = $x1; + $dx = $x2 - $x1; + } else { + $rtb = $x2; + $dx = $x1 - $x2; + } + + for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { + $dx *= 0.5; + $x_mid = $rtb + $dx; + $f_mid = self::NPV($x_mid, $values); + if ($f_mid <= 0.0) $rtb = $x_mid; + if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) return $x_mid; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function IRR() + + + /** + * ISPMT + * + * Returns the interest payment for an investment based on an interest rate and a constant payment schedule. + * + * Excel Function: + * =ISPMT(interest_rate, period, number_payments, PV) + * + * interest_rate is the interest rate for the investment + * + * period is the period to calculate the interest rate. It must be betweeen 1 and number_payments. + * + * number_payments is the number of payments for the annuity + * + * PV is the loan amount or present value of the payments + */ + public static function ISPMT() { + // Return value + $returnValue = 0; + + // Get the parameters + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + $interestRate = array_shift($aArgs); + $period = array_shift($aArgs); + $numberPeriods = array_shift($aArgs); + $principleRemaining = array_shift($aArgs); + + // Calculate + $principlePayment = ($principleRemaining * 1.0) / ($numberPeriods * 1.0); + for($i=0; $i <= $period; ++$i) { + $returnValue = $interestRate * $principleRemaining * -1; + $principleRemaining -= $principlePayment; + // principle needs to be 0 after the last payment, don't let floating point screw it up + if($i == $numberPeriods) { + $returnValue = 0; + } + } + return($returnValue); + } // function ISPMT() + + + public static function MIRR($values, $finance_rate, $reinvestment_rate) { + if (!is_array($values)) return PHPExcel_Calculation_Functions::VALUE(); + $values = PHPExcel_Calculation_Functions::flattenArray($values); + $finance_rate = PHPExcel_Calculation_Functions::flattenSingleValue($finance_rate); + $reinvestment_rate = PHPExcel_Calculation_Functions::flattenSingleValue($reinvestment_rate); + $n = count($values); + + $rr = 1.0 + $reinvestment_rate; + $fr = 1.0 + $finance_rate; + + $npv_pos = $npv_neg = 0.0; + foreach($values as $i => $v) { + if ($v >= 0) { + $npv_pos += $v / pow($rr, $i); + } else { + $npv_neg += $v / pow($fr, $i); + } + } + + if (($npv_neg == 0) || ($npv_pos == 0) || ($reinvestment_rate <= -1)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + $mirr = pow((-$npv_pos * pow($rr, $n)) + / ($npv_neg * ($rr)), (1.0 / ($n - 1))) - 1.0; + + return (is_finite($mirr) ? $mirr : PHPExcel_Calculation_Functions::VALUE()); + } // function MIRR() + + + /** + * NOMINAL + * + * Returns the nominal interest rate given the effective rate and the number of compounding payments per year. + * + * @param float $effect_rate Effective interest rate + * @param int $npery Number of compounding payments per year + * @return float + */ + public static function NOMINAL($effect_rate = 0, $npery = 0) { + $effect_rate = PHPExcel_Calculation_Functions::flattenSingleValue($effect_rate); + $npery = (int)PHPExcel_Calculation_Functions::flattenSingleValue($npery); + + // Validate parameters + if ($effect_rate <= 0 || $npery < 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Calculate + return $npery * (pow($effect_rate + 1, 1 / $npery) - 1); + } // function NOMINAL() + + + /** + * NPER + * + * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate. + * + * @param float $rate Interest rate per period + * @param int $pmt Periodic payment (annuity) + * @param float $pv Present Value + * @param float $fv Future Value + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv); + $type = PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Calculate + if (!is_null($rate) && $rate != 0) { + if ($pmt == 0 && $pv == 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate)) / log(1 + $rate); + } else { + if ($pmt == 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return (-$pv -$fv) / $pmt; + } + } // function NPER() + + + /** + * NPV + * + * Returns the Net Present Value of a cash flow series given a discount rate. + * + * @param float Discount interest rate + * @param array Cash flow series + * @return float + */ + public static function NPV() { + // Return value + $returnValue = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + // Calculate + $rate = array_shift($aArgs); + for ($i = 1; $i <= count($aArgs); ++$i) { + // Is it a numeric value? + if (is_numeric($aArgs[$i - 1])) { + $returnValue += $aArgs[$i - 1] / pow(1 + $rate, $i); + } + } + + // Return + return $returnValue; + } // function NPV() + + + /** + * PMT + * + * Returns the constant payment (annuity) for a cash flow with a constant interest rate. + * + * @param float $rate Interest rate per period + * @param int $nper Number of periods + * @param float $pv Present Value + * @param float $fv Future Value + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv); + $type = PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Calculate + if (!is_null($rate) && $rate != 0) { + return (-$fv - $pv * pow(1 + $rate, $nper)) / (1 + $rate * $type) / ((pow(1 + $rate, $nper) - 1) / $rate); + } else { + return (-$pv - $fv) / $nper; + } + } // function PMT() + + + /** + * PPMT + * + * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate. + * + * @param float $rate Interest rate per period + * @param int $per Period for which we want to find the interest + * @param int $nper Number of periods + * @param float $pv Present Value + * @param float $fv Future Value + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $per = (int) PHPExcel_Calculation_Functions::flattenSingleValue($per); + $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv); + $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($per <= 0 || $per > $nper) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Calculate + $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type); + return $interestAndPrincipal[1]; + } // function PPMT() + + + public static function PRICE($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $rate = (float) PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $yield = (float) PHPExcel_Calculation_Functions::flattenSingleValue($yield); + $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption); + $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency); + $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + if (is_string($settlement = PHPExcel_Calculation_DateTime::_getDateValue($settlement))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (($settlement > $maturity) || + (!self::_validFrequency($frequency)) || + (($basis < 0) || ($basis > 4))) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $dsc = self::COUPDAYSNC($settlement, $maturity, $frequency, $basis); + $e = self::COUPDAYS($settlement, $maturity, $frequency, $basis); + $n = self::COUPNUM($settlement, $maturity, $frequency, $basis); + $a = self::COUPDAYBS($settlement, $maturity, $frequency, $basis); + + $baseYF = 1.0 + ($yield / $frequency); + $rfp = 100 * ($rate / $frequency); + $de = $dsc / $e; + + $result = $redemption / pow($baseYF, (--$n + $de)); + for($k = 0; $k <= $n; ++$k) { + $result += $rfp / (pow($baseYF, ($k + $de))); + } + $result -= $rfp * ($a / $e); + + return $result; + } // function PRICE() + + + /** + * PRICEDISC + * + * Returns the price per $100 face value of a discounted security. + * + * @param mixed settlement The security's settlement date. + * The security settlement date is the date after the issue date when the security is traded to the buyer. + * @param mixed maturity The security's maturity date. + * The maturity date is the date when the security expires. + * @param int discount The security's discount rate. + * @param int redemption The security's redemption value per $100 face value. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $discount = (float) PHPExcel_Calculation_Functions::flattenSingleValue($discount); + $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption); + $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) { + if (($discount <= 0) || ($redemption <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function PRICEDISC() + + + /** + * PRICEMAT + * + * Returns the price per $100 face value of a security that pays interest at maturity. + * + * @param mixed settlement The security's settlement date. + * The security's settlement date is the date after the issue date when the security is traded to the buyer. + * @param mixed maturity The security's maturity date. + * The maturity date is the date when the security expires. + * @param mixed issue The security's issue date. + * @param int rate The security's interest rate at date of issue. + * @param int yield The security's annual yield. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue); + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $yield = PHPExcel_Calculation_Functions::flattenSingleValue($yield); + $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if (is_numeric($rate) && is_numeric($yield)) { + if (($rate <= 0) || ($yield <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis); + if (!is_numeric($daysPerYear)) { + return $daysPerYear; + } + $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + $daysBetweenIssueAndSettlement *= $daysPerYear; + $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $maturity, $basis); + if (!is_numeric($daysBetweenIssueAndMaturity)) { + // return date error + return $daysBetweenIssueAndMaturity; + } + $daysBetweenIssueAndMaturity *= $daysPerYear; + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + $daysBetweenSettlementAndMaturity *= $daysPerYear; + + return ((100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) / + (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) - + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function PRICEMAT() + + + /** + * PV + * + * Returns the Present Value of a cash flow with constant payments and interest rate (annuities). + * + * @param float $rate Interest rate per period + * @param int $nper Number of periods + * @param float $pmt Periodic payment (annuity) + * @param float $fv Future Value + * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @return float + */ + public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt); + $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv); + $type = PHPExcel_Calculation_Functions::flattenSingleValue($type); + + // Validate parameters + if ($type != 0 && $type != 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + + // Calculate + if (!is_null($rate) && $rate != 0) { + return (-$pmt * (1 + $rate * $type) * ((pow(1 + $rate, $nper) - 1) / $rate) - $fv) / pow(1 + $rate, $nper); + } else { + return -$fv - $pmt * $nper; + } + } // function PV() + + + /** + * RATE + * + **/ + public static function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) { + $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper); + $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt); + $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv); + $fv = (is_null($fv)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($fv); + $type = (is_null($type)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($type); + $guess = (is_null($guess)) ? 0.1 : PHPExcel_Calculation_Functions::flattenSingleValue($guess); + + $rate = $guess; + if (abs($rate) < FINANCIAL_PRECISION) { + $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv; + } else { + $f = exp($nper * log(1 + $rate)); + $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv; + } + $y0 = $pv + $pmt * $nper + $fv; + $y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv; + + // find root by secant method + $i = $x0 = 0.0; + $x1 = $rate; + while ((abs($y0 - $y1) > FINANCIAL_PRECISION) && ($i < FINANCIAL_MAX_ITERATIONS)) { + $rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0); + $x0 = $x1; + $x1 = $rate; + + if (abs($rate) < FINANCIAL_PRECISION) { + $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv; + } else { + $f = exp($nper * log(1 + $rate)); + $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv; + } + + $y0 = $y1; + $y1 = $y; + ++$i; + } + return $rate; + } // function RATE() + + + /** + * RECEIVED + * + * Returns the price per $100 face value of a discounted security. + * + * @param mixed settlement The security's settlement date. + * The security settlement date is the date after the issue date when the security is traded to the buyer. + * @param mixed maturity The security's maturity date. + * The maturity date is the date when the security expires. + * @param int investment The amount invested in the security. + * @param int discount The security's discount rate. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $investment = (float) PHPExcel_Calculation_Functions::flattenSingleValue($investment); + $discount = (float) PHPExcel_Calculation_Functions::flattenSingleValue($discount); + $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) { + if (($investment <= 0) || ($discount <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return $investment / ( 1 - ($discount * $daysBetweenSettlementAndMaturity)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function RECEIVED() + + + /** + * SLN + * + * Returns the straight-line depreciation of an asset for one period + * + * @param cost Initial cost of the asset + * @param salvage Value at the end of the depreciation + * @param life Number of periods over which the asset is depreciated + * @return float + */ + public static function SLN($cost, $salvage, $life) { + $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost); + $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage); + $life = PHPExcel_Calculation_Functions::flattenSingleValue($life); + + // Calculate + if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) { + if ($life < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return ($cost - $salvage) / $life; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SLN() + + + /** + * SYD + * + * Returns the sum-of-years' digits depreciation of an asset for a specified period. + * + * @param cost Initial cost of the asset + * @param salvage Value at the end of the depreciation + * @param life Number of periods over which the asset is depreciated + * @param period Period + * @return float + */ + public static function SYD($cost, $salvage, $life, $period) { + $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost); + $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage); + $life = PHPExcel_Calculation_Functions::flattenSingleValue($life); + $period = PHPExcel_Calculation_Functions::flattenSingleValue($period); + + // Calculate + if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) { + if (($life < 1) || ($period > $life)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SYD() + + + /** + * TBILLEQ + * + * Returns the bond-equivalent yield for a Treasury bill. + * + * @param mixed settlement The Treasury bill's settlement date. + * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. + * @param mixed maturity The Treasury bill's maturity date. + * The maturity date is the date when the Treasury bill expires. + * @param int discount The Treasury bill's discount rate. + * @return float + */ + public static function TBILLEQ($settlement, $maturity, $discount) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $discount = PHPExcel_Calculation_Functions::flattenSingleValue($discount); + + // Use TBILLPRICE for validation + $testValue = self::TBILLPRICE($settlement, $maturity, $discount); + if (is_string($testValue)) { + return $testValue; + } + + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + ++$maturity; + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360; + } else { + $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::_getDateValue($maturity) - PHPExcel_Calculation_DateTime::_getDateValue($settlement)); + } + + return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity); + } // function TBILLEQ() + + + /** + * TBILLPRICE + * + * Returns the yield for a Treasury bill. + * + * @param mixed settlement The Treasury bill's settlement date. + * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. + * @param mixed maturity The Treasury bill's maturity date. + * The maturity date is the date when the Treasury bill expires. + * @param int discount The Treasury bill's discount rate. + * @return float + */ + public static function TBILLPRICE($settlement, $maturity, $discount) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $discount = PHPExcel_Calculation_Functions::flattenSingleValue($discount); + + if (is_string($maturity = PHPExcel_Calculation_DateTime::_getDateValue($maturity))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Validate + if (is_numeric($discount)) { + if ($discount <= 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + ++$maturity; + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360; + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + } else { + $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::_getDateValue($maturity) - PHPExcel_Calculation_DateTime::_getDateValue($settlement)); + } + + if ($daysBetweenSettlementAndMaturity > 360) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360)); + if ($price <= 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return $price; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function TBILLPRICE() + + + /** + * TBILLYIELD + * + * Returns the yield for a Treasury bill. + * + * @param mixed settlement The Treasury bill's settlement date. + * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. + * @param mixed maturity The Treasury bill's maturity date. + * The maturity date is the date when the Treasury bill expires. + * @param int price The Treasury bill's price per $100 face value. + * @return float + */ + public static function TBILLYIELD($settlement, $maturity, $price) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $price = PHPExcel_Calculation_Functions::flattenSingleValue($price); + + // Validate + if (is_numeric($price)) { + if ($price <= 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + ++$maturity; + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360; + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + } else { + $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::_getDateValue($maturity) - PHPExcel_Calculation_DateTime::_getDateValue($settlement)); + } + + if ($daysBetweenSettlementAndMaturity > 360) { + return PHPExcel_Calculation_Functions::NaN(); + } + + return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function TBILLYIELD() + + + public static function XIRR($values, $dates, $guess = 0.1) { + if ((!is_array($values)) && (!is_array($dates))) return PHPExcel_Calculation_Functions::VALUE(); + $values = PHPExcel_Calculation_Functions::flattenArray($values); + $dates = PHPExcel_Calculation_Functions::flattenArray($dates); + $guess = PHPExcel_Calculation_Functions::flattenSingleValue($guess); + if (count($values) != count($dates)) return PHPExcel_Calculation_Functions::NaN(); + + // create an initial range, with a root somewhere between 0 and guess + $x1 = 0.0; + $x2 = $guess; + $f1 = self::XNPV($x1, $values, $dates); + $f2 = self::XNPV($x2, $values, $dates); + for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { + if (($f1 * $f2) < 0.0) break; + if (abs($f1) < abs($f2)) { + $f1 = self::XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates); + } else { + $f2 = self::XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates); + } + } + if (($f1 * $f2) > 0.0) return PHPExcel_Calculation_Functions::VALUE(); + + $f = self::XNPV($x1, $values, $dates); + if ($f < 0.0) { + $rtb = $x1; + $dx = $x2 - $x1; + } else { + $rtb = $x2; + $dx = $x1 - $x2; + } + + for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { + $dx *= 0.5; + $x_mid = $rtb + $dx; + $f_mid = self::XNPV($x_mid, $values, $dates); + if ($f_mid <= 0.0) $rtb = $x_mid; + if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) return $x_mid; + } + return PHPExcel_Calculation_Functions::VALUE(); + } + + + /** + * XNPV + * + * Returns the net present value for a schedule of cash flows that is not necessarily periodic. + * To calculate the net present value for a series of cash flows that is periodic, use the NPV function. + * + * Excel Function: + * =XNPV(rate,values,dates) + * + * @param float $rate The discount rate to apply to the cash flows. + * @param array of float $values A series of cash flows that corresponds to a schedule of payments in dates. The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year. The series of values must contain at least one positive value and one negative value. + * @param array of mixed $dates A schedule of payment dates that corresponds to the cash flow payments. The first payment date indicates the beginning of the schedule of payments. All other dates must be later than this date, but they may occur in any order. + * @return float + */ + public static function XNPV($rate, $values, $dates) { + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + if (!is_numeric($rate)) return PHPExcel_Calculation_Functions::VALUE(); + if ((!is_array($values)) || (!is_array($dates))) return PHPExcel_Calculation_Functions::VALUE(); + $values = PHPExcel_Calculation_Functions::flattenArray($values); + $dates = PHPExcel_Calculation_Functions::flattenArray($dates); + $valCount = count($values); + if ($valCount != count($dates)) return PHPExcel_Calculation_Functions::NaN(); + if ((min($values) > 0) || (max($values) < 0)) return PHPExcel_Calculation_Functions::VALUE(); + + $xnpv = 0.0; + for ($i = 0; $i < $valCount; ++$i) { + if (!is_numeric($values[$i])) return PHPExcel_Calculation_Functions::VALUE(); + $xnpv += $values[$i] / pow(1 + $rate, PHPExcel_Calculation_DateTime::DATEDIF($dates[0],$dates[$i],'d') / 365); + } + return (is_finite($xnpv)) ? $xnpv : PHPExcel_Calculation_Functions::VALUE(); + } // function XNPV() + + + /** + * YIELDDISC + * + * Returns the annual yield of a security that pays interest at maturity. + * + * @param mixed settlement The security's settlement date. + * The security's settlement date is the date after the issue date when the security is traded to the buyer. + * @param mixed maturity The security's maturity date. + * The maturity date is the date when the security expires. + * @param int price The security's price per $100 face value. + * @param int redemption The security's redemption value per $100 face value. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $price = PHPExcel_Calculation_Functions::flattenSingleValue($price); + $redemption = PHPExcel_Calculation_Functions::flattenSingleValue($redemption); + $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if (is_numeric($price) && is_numeric($redemption)) { + if (($price <= 0) || ($redemption <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis); + if (!is_numeric($daysPerYear)) { + return $daysPerYear; + } + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity,$basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + $daysBetweenSettlementAndMaturity *= $daysPerYear; + + return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function YIELDDISC() + + + /** + * YIELDMAT + * + * Returns the annual yield of a security that pays interest at maturity. + * + * @param mixed settlement The security's settlement date. + * The security's settlement date is the date after the issue date when the security is traded to the buyer. + * @param mixed maturity The security's maturity date. + * The maturity date is the date when the security expires. + * @param mixed issue The security's issue date. + * @param int rate The security's interest rate at date of issue. + * @param int price The security's price per $100 face value. + * @param int basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @return float + */ + public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis=0) { + $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement); + $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity); + $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue); + $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate); + $price = PHPExcel_Calculation_Functions::flattenSingleValue($price); + $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis); + + // Validate + if (is_numeric($rate) && is_numeric($price)) { + if (($rate <= 0) || ($price <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $daysPerYear = self::_daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement),$basis); + if (!is_numeric($daysPerYear)) { + return $daysPerYear; + } + $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + $daysBetweenIssueAndSettlement *= $daysPerYear; + $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $maturity, $basis); + if (!is_numeric($daysBetweenIssueAndMaturity)) { + // return date error + return $daysBetweenIssueAndMaturity; + } + $daysBetweenIssueAndMaturity *= $daysPerYear; + $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + $daysBetweenSettlementAndMaturity *= $daysPerYear; + + return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) / + (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) * + ($daysPerYear / $daysBetweenSettlementAndMaturity); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function YIELDMAT() + +} // class PHPExcel_Calculation_Financial diff --git a/libraries/PHPExcel/PHPExcel/Calculation/FormulaParser.php b/libraries/PHPExcel/PHPExcel/Calculation/FormulaParser.php index 271aa7524..f8ffe579f 100644 --- a/libraries/PHPExcel/PHPExcel/Calculation/FormulaParser.php +++ b/libraries/PHPExcel/PHPExcel/Calculation/FormulaParser.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -54,7 +54,7 @@ PARTLY BASED ON: * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Calculation_FormulaParser { /* Character constants */ diff --git a/libraries/PHPExcel/PHPExcel/Calculation/FormulaToken.php b/libraries/PHPExcel/PHPExcel/Calculation/FormulaToken.php index 8c1396e67..3045a9a89 100644 --- a/libraries/PHPExcel/PHPExcel/Calculation/FormulaToken.php +++ b/libraries/PHPExcel/PHPExcel/Calculation/FormulaToken.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -55,7 +55,7 @@ PARTLY BASED ON: * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Calculation_FormulaToken { /* Token types */ diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Function.php b/libraries/PHPExcel/PHPExcel/Calculation/Function.php index 81dfc99bd..14c9294f2 100644 --- a/libraries/PHPExcel/PHPExcel/Calculation/Function.php +++ b/libraries/PHPExcel/PHPExcel/Calculation/Function.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Calculation_Function { /* Function categories */ diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Functions.php b/libraries/PHPExcel/PHPExcel/Calculation/Functions.php index 805f483a8..beab5a6ab 100644 --- a/libraries/PHPExcel/PHPExcel/Calculation/Functions.php +++ b/libraries/PHPExcel/PHPExcel/Calculation/Functions.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,55 +33,20 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } -/** EPS */ -define('EPS', 2.22e-16); - /** MAX_VALUE */ define('MAX_VALUE', 1.2e308); -/** LOG_GAMMA_X_MAX_VALUE */ -define('LOG_GAMMA_X_MAX_VALUE', 2.55e305); - -/** SQRT2PI */ -define('SQRT2PI', 2.5066282746310005024157652848110452530069867406099); - /** 2 / PI */ define('M_2DIVPI', 0.63661977236758134307553505349006); -/** XMININ */ -define('XMININ', 2.23e-308); - /** MAX_ITERATIONS */ define('MAX_ITERATIONS', 256); -/** FINANCIAL_MAX_ITERATIONS */ -define('FINANCIAL_MAX_ITERATIONS', 128); /** PRECISION */ define('PRECISION', 8.88E-016); -/** FINANCIAL_PRECISION */ -define('FINANCIAL_PRECISION', 1.0e-08); - -/** EULER */ -define('EULER', 2.71828182845904523536); - -$savedPrecision = ini_get('precision'); -if ($savedPrecision < 16) { - ini_set('precision',16); -} - - -/** Matrix */ -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/Matrix.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/trendClass.php'; /** @@ -89,7 +54,7 @@ require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/trendClass.php'; * * @category PHPExcel * @package PHPExcel_Calculation - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Calculation_Functions { @@ -109,7 +74,7 @@ class PHPExcel_Calculation_Functions { * @access private * @var string */ - private static $compatibilityMode = self::COMPATIBILITY_EXCEL; + protected static $compatibilityMode = self::COMPATIBILITY_EXCEL; /** * Data Type to use when returning date values @@ -117,7 +82,7 @@ class PHPExcel_Calculation_Functions { * @access private * @var string */ - private static $ReturnDateType = self::RETURNDATE_EXCEL; + protected static $ReturnDateType = self::RETURNDATE_EXCEL; /** * List of error codes @@ -125,15 +90,15 @@ class PHPExcel_Calculation_Functions { * @access private * @var array */ - private static $_errorCodes = array( 'null' => '#NULL!', - 'divisionbyzero' => '#DIV/0!', - 'value' => '#VALUE!', - 'reference' => '#REF!', - 'name' => '#NAME?', - 'num' => '#NUM!', - 'na' => '#N/A', - 'gettingdata' => '#GETTING_DATA' - ); + protected static $_errorCodes = array( 'null' => '#NULL!', + 'divisionbyzero' => '#DIV/0!', + 'value' => '#VALUE!', + 'reference' => '#REF!', + 'name' => '#NAME?', + 'num' => '#NUM!', + 'na' => '#N/A', + 'gettingdata' => '#GETTING_DATA' + ); /** @@ -226,6 +191,18 @@ class PHPExcel_Calculation_Functions { } // function DUMMY() + /** + * DIV0 + * + * @access public + * @category Error Returns + * @return string #Not Yet Implemented + */ + public static function DIV0() { + return self::$_errorCodes['divisionbyzero']; + } // function DIV0() + + /** * NA * @@ -245,7 +222,7 @@ class PHPExcel_Calculation_Functions { /** - * NAN + * NaN * * Returns the error value #NUM! * @@ -255,7 +232,7 @@ class PHPExcel_Calculation_Functions { */ public static function NaN() { return self::$_errorCodes['num']; - } // function NAN() + } // function NaN() /** @@ -286,6 +263,20 @@ class PHPExcel_Calculation_Functions { } // function REF() + /** + * NULL + * + * Returns the error value #NULL! + * + * @access public + * @category Error Returns + * @return string #REF! + */ + public static function NULL() { + return self::$_errorCodes['null']; + } // function NULL() + + /** * VALUE * @@ -300,733 +291,23 @@ class PHPExcel_Calculation_Functions { } // function VALUE() - private static function isMatrixValue($idx) { + public static function isMatrixValue($idx) { return ((substr_count($idx,'.') <= 1) || (preg_match('/\.[A-Z]/',$idx) > 0)); } - private static function isValue($idx) { + public static function isValue($idx) { return (substr_count($idx,'.') == 0); } - private static function isCellValue($idx) { + public static function isCellValue($idx) { return (substr_count($idx,'.') > 1); } - /** - * LOGICAL_AND - * - * Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE. - * - * Excel Function: - * =AND(logical1[,logical2[, ...]]) - * - * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays - * or references that contain logical values. - * - * Boolean arguments are treated as True or False as appropriate - * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False - * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds - * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value - * - * @access public - * @category Logical Functions - * @param mixed $arg,... Data values - * @return boolean The logical AND of the arguments. - */ - public static function LOGICAL_AND() { - // Return value - $returnValue = True; - - // Loop through the arguments - $aArgs = self::flattenArray(func_get_args()); - $argCount = 0; - foreach ($aArgs as $arg) { - // Is it a boolean value? - if (is_bool($arg)) { - $returnValue = $returnValue && $arg; - } elseif ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue = $returnValue && ($arg != 0); - } elseif (is_string($arg)) { - $arg = strtoupper($arg); - if ($arg == 'TRUE') { - $arg = 1; - } elseif ($arg == 'FALSE') { - $arg = 0; - } else { - return self::$_errorCodes['value']; - } - $returnValue = $returnValue && ($arg != 0); - } - ++$argCount; - } - - // Return - if ($argCount == 0) { - return self::$_errorCodes['value']; - } - return $returnValue; - } // function LOGICAL_AND() - - - /** - * LOGICAL_OR - * - * Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE. - * - * Excel Function: - * =OR(logical1[,logical2[, ...]]) - * - * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays - * or references that contain logical values. - * - * Boolean arguments are treated as True or False as appropriate - * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False - * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds - * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value - * - * @access public - * @category Logical Functions - * @param mixed $arg,... Data values - * @return boolean The logical OR of the arguments. - */ - public static function LOGICAL_OR() { - // Return value - $returnValue = False; - - // Loop through the arguments - $aArgs = self::flattenArray(func_get_args()); - $argCount = 0; - foreach ($aArgs as $arg) { - // Is it a boolean value? - if (is_bool($arg)) { - $returnValue = $returnValue || $arg; - } elseif ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue = $returnValue || ($arg != 0); - } elseif (is_string($arg)) { - $arg = strtoupper($arg); - if ($arg == 'TRUE') { - $arg = 1; - } elseif ($arg == 'FALSE') { - $arg = 0; - } else { - return self::$_errorCodes['value']; - } - $returnValue = $returnValue || ($arg != 0); - } - ++$argCount; - } - - // Return - if ($argCount == 0) { - return self::$_errorCodes['value']; - } - return $returnValue; - } // function LOGICAL_OR() - - - /** - * LOGICAL_FALSE - * - * Returns the boolean FALSE. - * - * Excel Function: - * =FALSE() - * - * @access public - * @category Logical Functions - * @return boolean False - */ - public static function LOGICAL_FALSE() { - return False; - } // function LOGICAL_FALSE() - - - /** - * LOGICAL_TRUE - * - * Returns the boolean TRUE. - * - * Excel Function: - * =TRUE() - * - * @access public - * @category Logical Functions - * @return boolean True - */ - public static function LOGICAL_TRUE() { - return True; - } // function LOGICAL_TRUE() - - - /** - * LOGICAL_NOT - * - * Returns the boolean inverse of the argument. - * - * Excel Function: - * =NOT(logical) - * - * The argument must evaluate to a logical value such as TRUE or FALSE - * - * Boolean arguments are treated as True or False as appropriate - * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False - * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds - * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value - * - * @access public - * @category Logical Functions - * @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE - * @return boolean The boolean inverse of the argument. - */ - public static function LOGICAL_NOT($logical) { - $logical = self::flattenSingleValue($logical); - if (is_string($logical)) { - $logical = strtoupper($logical); - if ($logical == 'TRUE') { - return False; - } elseif ($logical == 'FALSE') { - return True; - } else { - return self::$_errorCodes['value']; - } - } - - return !$logical; - } // function LOGICAL_NOT() - - - /** - * STATEMENT_IF - * - * Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE. - * - * Excel Function: - * =IF(condition[,returnIfTrue[,returnIfFalse]]) - * - * Condition is any value or expression that can be evaluated to TRUE or FALSE. - * For example, A10=100 is a logical expression; if the value in cell A10 is equal to 100, - * the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE. - * This argument can use any comparison calculation operator. - * ReturnIfTrue is the value that is returned if condition evaluates to TRUE. - * For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE, - * then the IF function returns the text "Within budget" - * If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use - * the logical value TRUE for this argument. - * ReturnIfTrue can be another formula. - * ReturnIfFalse is the value that is returned if condition evaluates to FALSE. - * For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE, - * then the IF function returns the text "Over budget". - * If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned. - * If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned. - * ReturnIfFalse can be another formula. - * - * @access public - * @category Logical Functions - * @param mixed $condition Condition to evaluate - * @param mixed $returnIfTrue Value to return when condition is true - * @param mixed $returnIfFalse Optional value to return when condition is false - * @return mixed The value of returnIfTrue or returnIfFalse determined by condition - */ - public static function STATEMENT_IF($condition = true, $returnIfTrue = 0, $returnIfFalse = False) { - $condition = (is_null($condition)) ? True : (boolean) self::flattenSingleValue($condition); - $returnIfTrue = (is_null($returnIfTrue)) ? 0 : self::flattenSingleValue($returnIfTrue); - $returnIfFalse = (is_null($returnIfFalse)) ? False : self::flattenSingleValue($returnIfFalse); - - return ($condition ? $returnIfTrue : $returnIfFalse); - } // function STATEMENT_IF() - - - /** - * STATEMENT_IFERROR - * - * Excel Function: - * =IFERROR(testValue,errorpart) - * - * @access public - * @category Logical Functions - * @param mixed $testValue Value to check, is also the value returned when no error - * @param mixed $errorpart Value to return when testValue is an error condition - * @return mixed The value of errorpart or testValue determined by error condition - */ - public static function STATEMENT_IFERROR($testValue = '', $errorpart = '') { - $testValue = (is_null($testValue)) ? '' : self::flattenSingleValue($testValue); - $errorpart = (is_null($errorpart)) ? '' : self::flattenSingleValue($errorpart); - - return self::STATEMENT_IF(self::IS_ERROR($testValue), $errorpart, $testValue); - } // function STATEMENT_IFERROR() - - - /** - * HYPERLINK - * - * Excel Function: - * =HYPERLINK(linkURL,displayName) - * - * @access public - * @category Logical Functions - * @param string $linkURL Value to check, is also the value returned when no error - * @param string $displayName Value to return when testValue is an error condition - * @return mixed The value of errorpart or testValue determined by error condition - */ - public static function HYPERLINK($linkURL = '', $displayName = null, PHPExcel_Cell $pCell = null) { - $args = func_get_args(); - $pCell = array_pop($args); - - $linkURL = (is_null($linkURL)) ? '' : self::flattenSingleValue($linkURL); - $displayName = (is_null($displayName)) ? '' : self::flattenSingleValue($displayName); - - if ((!is_object($pCell)) || (trim($linkURL) == '')) { - return self::$_errorCodes['reference']; - } - - if ((is_object($displayName)) || trim($displayName) == '') { - $displayName = $linkURL; - } - - $pCell->getHyperlink()->setUrl($linkURL); - - return $displayName; - } // function HYPERLINK() - - - /** - * ATAN2 - * - * This function calculates the arc tangent of the two variables x and y. It is similar to - * calculating the arc tangent of y ÷ x, except that the signs of both arguments are used - * to determine the quadrant of the result. - * The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a - * point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between - * -pi and pi, excluding -pi. - * - * Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard - * PHP atan2() function, so we need to reverse them here before calling the PHP atan() function. - * - * Excel Function: - * ATAN2(xCoordinate,yCoordinate) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param float $xCoordinate The x-coordinate of the point. - * @param float $yCoordinate The y-coordinate of the point. - * @return float The inverse tangent of the specified x- and y-coordinates. - */ - public static function REVERSE_ATAN2($xCoordinate, $yCoordinate) { - $xCoordinate = (float) self::flattenSingleValue($xCoordinate); - $yCoordinate = (float) self::flattenSingleValue($yCoordinate); - - if (($xCoordinate == 0) && ($yCoordinate == 0)) { - return self::$_errorCodes['divisionbyzero']; - } - - return atan2($yCoordinate, $xCoordinate); - } // function REVERSE_ATAN2() - - - /** - * LOG_BASE - * - * Returns the logarithm of a number to a specified base. The default base is 10. - * - * Excel Function: - * LOG(number[,base]) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param float $value The positive real number for which you want the logarithm - * @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10. - * @return float - */ - public static function LOG_BASE($number, $base=10) { - $number = self::flattenSingleValue($number); - $base = (is_null($base)) ? 10 : (float) self::flattenSingleValue($base); - - return log($number, $base); - } // function LOG_BASE() - - - /** - * SUM - * - * SUM computes the sum of all the values and cells referenced in the argument list. - * - * Excel Function: - * SUM(value1[,value2[, ...]]) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function SUM() { - // Return value - $returnValue = 0; - - // Loop through the arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += $arg; - } - } - - // Return - return $returnValue; - } // function SUM() - - - /** - * SUMSQ - * - * SUMSQ returns the sum of the squares of the arguments - * - * Excel Function: - * SUMSQ(value1[,value2[, ...]]) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function SUMSQ() { - // Return value - $returnValue = 0; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += ($arg * $arg); - } - } - - // Return - return $returnValue; - } // function SUMSQ() - - - /** - * PRODUCT - * - * PRODUCT returns the product of all the values and cells referenced in the argument list. - * - * Excel Function: - * PRODUCT(value1[,value2[, ...]]) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function PRODUCT() { - // Return value - $returnValue = null; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (is_null($returnValue)) { - $returnValue = $arg; - } else { - $returnValue *= $arg; - } - } - } - - // Return - if (is_null($returnValue)) { - return 0; - } - return $returnValue; - } // function PRODUCT() - - - /** - * QUOTIENT - * - * QUOTIENT function returns the integer portion of a division. Numerator is the divided number - * and denominator is the divisor. - * - * Excel Function: - * QUOTIENT(value1[,value2[, ...]]) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function QUOTIENT() { - // Return value - $returnValue = null; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (is_null($returnValue)) { - $returnValue = ($arg == 0) ? 0 : $arg; - } else { - if (($returnValue == 0) || ($arg == 0)) { - $returnValue = 0; - } else { - $returnValue /= $arg; - } - } - } - } - - // Return - return intval($returnValue); - } // function QUOTIENT() - - - /** - * MIN - * - * MIN returns the value of the element of the values passed that has the smallest value, - * with negative numbers considered smaller than positive numbers. - * - * Excel Function: - * MIN(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function MIN() { - // Return value - $returnValue = null; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if ((is_null($returnValue)) || ($arg < $returnValue)) { - $returnValue = $arg; - } - } - } - - // Return - if(is_null($returnValue)) { - return 0; - } - return $returnValue; - } // function MIN() - - - /** - * MINA - * - * Returns the smallest value in a list of arguments, including numbers, text, and logical values - * - * Excel Function: - * MINA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function MINA() { - // Return value - $returnValue = null; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - if (is_bool($arg)) { - $arg = (integer) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if ((is_null($returnValue)) || ($arg < $returnValue)) { - $returnValue = $arg; - } - } - } - - // Return - if(is_null($returnValue)) { - return 0; - } - return $returnValue; - } // function MINA() - - - /** - * MINIF - * - * Returns the minimum value within a range of cells that contain numbers within the list of arguments - * - * Excel Function: - * MINIF(value1[,value2[, ...]],condition) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @param string $condition The criteria that defines which cells will be checked. - * @return float - */ - public static function MINIF($aArgs,$condition,$sumArgs = array()) { - // Return value - $returnValue = null; - - $aArgs = self::flattenArray($aArgs); - $sumArgs = self::flattenArray($sumArgs); - if (count($sumArgs) == 0) { - $sumArgs = $aArgs; - } - $condition = self::_ifCondition($condition); - // Loop through arguments - foreach ($aArgs as $key => $arg) { - if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } - $testCondition = '='.$arg.$condition; - if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - if ((is_null($returnValue)) || ($arg < $returnValue)) { - $returnValue = $arg; - } - } - } - - // Return - return $returnValue; - } // function MINIF() - - - /** - * SMALL - * - * Returns the nth smallest value in a data set. You can use this function to - * select a value based on its relative standing. - * - * Excel Function: - * SMALL(value1[,value2[, ...]],entry) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @param int $entry Position (ordered from the smallest) in the array or range of data to return - * @return float - */ - public static function SMALL() { - $aArgs = self::flattenArray(func_get_args()); - - // Calculate - $entry = array_pop($aArgs); - - if ((is_numeric($entry)) && (!is_string($entry))) { - $mArgs = array(); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - $count = self::COUNT($mArgs); - $entry = floor(--$entry); - if (($entry < 0) || ($entry >= $count) || ($count == 0)) { - return self::$_errorCodes['num']; - } - sort($mArgs); - return $mArgs[$entry]; - } - return self::$_errorCodes['value']; - } // function SMALL() - - - /** - * MAX - * - * MAX returns the value of the element of the values passed that has the highest value, - * with negative numbers considered smaller than positive numbers. - * - * Excel Function: - * MAX(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function MAX() { - // Return value - $returnValue = null; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if ((is_null($returnValue)) || ($arg > $returnValue)) { - $returnValue = $arg; - } - } - } - - // Return - if(is_null($returnValue)) { - return 0; - } - return $returnValue; - } // function MAX() - - - /** - * MAXA - * - * Returns the greatest value in a list of arguments, including numbers, text, and logical values - * - * Excel Function: - * MAXA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function MAXA() { - // Return value - $returnValue = null; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - if (is_bool($arg)) { - $arg = (integer) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if ((is_null($returnValue)) || ($arg > $returnValue)) { - $returnValue = $arg; - } - } - } - - // Return - if(is_null($returnValue)) { - return 0; - } - return $returnValue; - } // function MAXA() - - - private static function _ifCondition($condition) { - $condition = self::flattenSingleValue($condition); + public static function _ifCondition($condition) { + $condition = PHPExcel_Calculation_Functions::flattenSingleValue($condition); if (!in_array($condition{0},array('>', '<', '='))) { if (!is_numeric($condition)) { $condition = PHPExcel_Calculation::_wrapResult(strtoupper($condition)); } return '='.$condition; @@ -1038,4493 +319,6 @@ class PHPExcel_Calculation_Functions { } } // function _ifCondition() - /** - * MAXIF - * - * Counts the maximum value within a range of cells that contain numbers within the list of arguments - * - * Excel Function: - * MAXIF(value1[,value2[, ...]],condition) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @param string $condition The criteria that defines which cells will be checked. - * @return float - */ - public static function MAXIF($aArgs,$condition,$sumArgs = array()) { - // Return value - $returnValue = null; - - $aArgs = self::flattenArray($aArgs); - $sumArgs = self::flattenArray($sumArgs); - if (count($sumArgs) == 0) { - $sumArgs = $aArgs; - } - $condition = self::_ifCondition($condition); - // Loop through arguments - foreach ($aArgs as $key => $arg) { - if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } - $testCondition = '='.$arg.$condition; - if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - if ((is_null($returnValue)) || ($arg > $returnValue)) { - $returnValue = $arg; - } - } - } - - // Return - return $returnValue; - } // function MAXIF() - - - /** - * LARGE - * - * Returns the nth largest value in a data set. You can use this function to - * select a value based on its relative standing. - * - * Excel Function: - * LARGE(value1[,value2[, ...]],entry) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @param int $entry Position (ordered from the largest) in the array or range of data to return - * @return float - * - */ - public static function LARGE() { - $aArgs = self::flattenArray(func_get_args()); - - // Calculate - $entry = floor(array_pop($aArgs)); - - if ((is_numeric($entry)) && (!is_string($entry))) { - $mArgs = array(); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - $count = self::COUNT($mArgs); - $entry = floor(--$entry); - if (($entry < 0) || ($entry >= $count) || ($count == 0)) { - return self::$_errorCodes['num']; - } - rsort($mArgs); - return $mArgs[$entry]; - } - return self::$_errorCodes['value']; - } // function LARGE() - - - /** - * PERCENTILE - * - * Returns the nth percentile of values in a range.. - * - * Excel Function: - * PERCENTILE(value1[,value2[, ...]],entry) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @param float $entry Percentile value in the range 0..1, inclusive. - * @return float - */ - public static function PERCENTILE() { - $aArgs = self::flattenArray(func_get_args()); - - // Calculate - $entry = array_pop($aArgs); - - if ((is_numeric($entry)) && (!is_string($entry))) { - if (($entry < 0) || ($entry > 1)) { - return self::$_errorCodes['num']; - } - $mArgs = array(); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - $mValueCount = count($mArgs); - if ($mValueCount > 0) { - sort($mArgs); - $count = self::COUNT($mArgs); - $index = $entry * ($count-1); - $iBase = floor($index); - if ($index == $iBase) { - return $mArgs[$index]; - } else { - $iNext = $iBase + 1; - $iProportion = $index - $iBase; - return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion) ; - } - } - } - return self::$_errorCodes['value']; - } // function PERCENTILE() - - - /** - * QUARTILE - * - * Returns the quartile of a data set. - * - * Excel Function: - * QUARTILE(value1[,value2[, ...]],entry) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @param int $entry Quartile value in the range 1..3, inclusive. - * @return float - */ - public static function QUARTILE() { - $aArgs = self::flattenArray(func_get_args()); - - // Calculate - $entry = floor(array_pop($aArgs)); - - if ((is_numeric($entry)) && (!is_string($entry))) { - $entry /= 4; - if (($entry < 0) || ($entry > 1)) { - return self::$_errorCodes['num']; - } - return self::PERCENTILE($aArgs,$entry); - } - return self::$_errorCodes['value']; - } // function QUARTILE() - - - /** - * COUNT - * - * Counts the number of cells that contain numbers within the list of arguments - * - * Excel Function: - * COUNT(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return int - */ - public static function COUNT() { - // Return value - $returnValue = 0; - - // Loop through arguments - $aArgs = self::flattenArrayIndexed(func_get_args()); - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) { - $arg = (integer) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - ++$returnValue; - } - } - - // Return - return $returnValue; - } // function COUNT() - - - /** - * COUNTBLANK - * - * Counts the number of empty cells within the list of arguments - * - * Excel Function: - * COUNTBLANK(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return int - */ - public static function COUNTBLANK() { - // Return value - $returnValue = 0; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a blank cell? - if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) { - ++$returnValue; - } - } - - // Return - return $returnValue; - } // function COUNTBLANK() - - - /** - * COUNTA - * - * Counts the number of cells that are not empty within the list of arguments - * - * Excel Function: - * COUNTA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return int - */ - public static function COUNTA() { - // Return value - $returnValue = 0; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric, boolean or string value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - ++$returnValue; - } - } - - // Return - return $returnValue; - } // function COUNTA() - - - /** - * COUNTIF - * - * Counts the number of cells that contain numbers within the list of arguments - * - * Excel Function: - * COUNTIF(value1[,value2[, ...]],condition) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @param string $condition The criteria that defines which cells will be counted. - * @return int - */ - public static function COUNTIF($aArgs,$condition) { - // Return value - $returnValue = 0; - - $aArgs = self::flattenArray($aArgs); - $condition = self::_ifCondition($condition); - // Loop through arguments - foreach ($aArgs as $arg) { - if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } - $testCondition = '='.$arg.$condition; - if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - // Is it a value within our criteria - ++$returnValue; - } - } - - // Return - return $returnValue; - } // function COUNTIF() - - - /** - * SUMIF - * - * Counts the number of cells that contain numbers within the list of arguments - * - * Excel Function: - * SUMIF(value1[,value2[, ...]],condition) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @param string $condition The criteria that defines which cells will be summed. - * @return float - */ - public static function SUMIF($aArgs,$condition,$sumArgs = array()) { - // Return value - $returnValue = 0; - - $aArgs = self::flattenArray($aArgs); - $sumArgs = self::flattenArray($sumArgs); - if (count($sumArgs) == 0) { - $sumArgs = $aArgs; - } - $condition = self::_ifCondition($condition); - // Loop through arguments - foreach ($aArgs as $key => $arg) { - if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } - $testCondition = '='.$arg.$condition; - if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - // Is it a value within our criteria - $returnValue += $sumArgs[$key]; - } - } - - // Return - return $returnValue; - } // function SUMIF() - - - /** - * AVERAGE - * - * Returns the average (arithmetic mean) of the arguments - * - * Excel Function: - * AVERAGE(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function AVERAGE() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - - $returnValue = $aCount = 0; - // Loop through arguments - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) { - $arg = (integer) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (is_null($returnValue)) { - $returnValue = $arg; - } else { - $returnValue += $arg; - } - ++$aCount; - } - } - - // Return - if ($aCount > 0) { - return $returnValue / $aCount; - } else { - return self::$_errorCodes['divisionbyzero']; - } - } // function AVERAGE() - - - /** - * AVERAGEA - * - * Returns the average of its arguments, including numbers, text, and logical values - * - * Excel Function: - * AVERAGEA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function AVERAGEA() { - // Return value - $returnValue = null; - - // Loop through arguments - $aArgs = self::flattenArrayIndexed(func_get_args()); - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - (!self::isMatrixValue($k))) { - } else { - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - if (is_bool($arg)) { - $arg = (integer) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if (is_null($returnValue)) { - $returnValue = $arg; - } else { - $returnValue += $arg; - } - ++$aCount; - } - } - } - - // Return - if ($aCount > 0) { - return $returnValue / $aCount; - } else { - return self::$_errorCodes['divisionbyzero']; - } - } // function AVERAGEA() - - - /** - * AVERAGEIF - * - * Returns the average value from a range of cells that contain numbers within the list of arguments - * - * Excel Function: - * AVERAGEIF(value1[,value2[, ...]],condition) - * - * @access public - * @category Mathematical and Trigonometric Functions - * @param mixed $arg,... Data values - * @param string $condition The criteria that defines which cells will be checked. - * @return float - */ - public static function AVERAGEIF($aArgs,$condition,$averageArgs = array()) { - // Return value - $returnValue = 0; - - $aArgs = self::flattenArray($aArgs); - $averageArgs = self::flattenArray($averageArgs); - if (count($averageArgs) == 0) { - $averageArgs = $aArgs; - } - $condition = self::_ifCondition($condition); - // Loop through arguments - $aCount = 0; - foreach ($aArgs as $key => $arg) { - if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } - $testCondition = '='.$arg.$condition; - if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - if ((is_null($returnValue)) || ($arg > $returnValue)) { - $returnValue += $arg; - ++$aCount; - } - } - } - - // Return - if ($aCount > 0) { - return $returnValue / $aCount; - } else { - return self::$_errorCodes['divisionbyzero']; - } - } // function AVERAGEIF() - - - /** - * MEDIAN - * - * Returns the median of the given numbers. The median is the number in the middle of a set of numbers. - * - * Excel Function: - * MEDIAN(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function MEDIAN() { - // Return value - $returnValue = self::$_errorCodes['num']; - - $mArgs = array(); - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - - $mValueCount = count($mArgs); - if ($mValueCount > 0) { - sort($mArgs,SORT_NUMERIC); - $mValueCount = $mValueCount / 2; - if ($mValueCount == floor($mValueCount)) { - $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2; - } else { - $mValueCount == floor($mValueCount); - $returnValue = $mArgs[$mValueCount]; - } - } - - // Return - return $returnValue; - } // function MEDIAN() - - - // - // Special variant of array_count_values that isn't limited to strings and integers, - // but can work with floating point numbers as values - // - private static function _modeCalc($data) { - $frequencyArray = array(); - foreach($data as $datum) { - $found = False; - foreach($frequencyArray as $key => $value) { - if ((string) $value['value'] == (string) $datum) { - ++$frequencyArray[$key]['frequency']; - $found = True; - break; - } - } - if (!$found) { - $frequencyArray[] = array('value' => $datum, - 'frequency' => 1 ); - } - } - - foreach($frequencyArray as $key => $value) { - $frequencyList[$key] = $value['frequency']; - $valueList[$key] = $value['value']; - } - array_multisort($frequencyList, SORT_DESC, $valueList, SORT_ASC, SORT_NUMERIC, $frequencyArray); - - if ($frequencyArray[0]['frequency'] == 1) { - return self::NA(); - } - return $frequencyArray[0]['value']; - } // function _modeCalc() - - - /** - * MODE - * - * Returns the most frequently occurring, or repetitive, value in an array or range of data - * - * Excel Function: - * MODE(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function MODE() { - // Return value - $returnValue = self::NA(); - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - - $mArgs = array(); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - - if (count($mArgs) > 0) { - return self::_modeCalc($mArgs); - } - - // Return - return $returnValue; - } // function MODE() - - - /** - * DEVSQ - * - * Returns the sum of squares of deviations of data points from their sample mean. - * - * Excel Function: - * DEVSQ(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function DEVSQ() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - - // Return value - $returnValue = null; - - $aMean = self::AVERAGE($aArgs); - if ($aMean != self::$_errorCodes['divisionbyzero']) { - $aCount = -1; - foreach ($aArgs as $k => $arg) { - // Is it a numeric value? - if ((is_bool($arg)) && - ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) { - $arg = (integer) $arg; - } - if ((is_numeric($arg)) && (!is_string($arg))) { - if (is_null($returnValue)) { - $returnValue = pow(($arg - $aMean),2); - } else { - $returnValue += pow(($arg - $aMean),2); - } - ++$aCount; - } - } - - // Return - if (is_null($returnValue)) { - return self::$_errorCodes['num']; - } else { - return $returnValue; - } - } - return self::NA(); - } // function DEVSQ() - - - /** - * AVEDEV - * - * Returns the average of the absolute deviations of data points from their mean. - * AVEDEV is a measure of the variability in a data set. - * - * Excel Function: - * AVEDEV(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function AVEDEV() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - - // Return value - $returnValue = null; - - $aMean = self::AVERAGE($aArgs); - if ($aMean != self::$_errorCodes['divisionbyzero']) { - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) { - $arg = (integer) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (is_null($returnValue)) { - $returnValue = abs($arg - $aMean); - } else { - $returnValue += abs($arg - $aMean); - } - ++$aCount; - } - } - - // Return - if ($aCount == 0) { - return self::$_errorCodes['divisionbyzero']; - } - return $returnValue / $aCount; - } - return self::$_errorCodes['num']; - } // function AVEDEV() - - - /** - * GEOMEAN - * - * Returns the geometric mean of an array or range of positive data. For example, you - * can use GEOMEAN to calculate average growth rate given compound interest with - * variable rates. - * - * Excel Function: - * GEOMEAN(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function GEOMEAN() { - $aArgs = self::flattenArray(func_get_args()); - - $aMean = self::PRODUCT($aArgs); - if (is_numeric($aMean) && ($aMean > 0)) { - $aCount = self::COUNT($aArgs) ; - if (self::MIN($aArgs) > 0) { - return pow($aMean, (1 / $aCount)); - } - } - return self::$_errorCodes['num']; - } // GEOMEAN() - - - /** - * HARMEAN - * - * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the - * arithmetic mean of reciprocals. - * - * Excel Function: - * HARMEAN(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function HARMEAN() { - // Return value - $returnValue = self::NA(); - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - if (self::MIN($aArgs) < 0) { - return self::$_errorCodes['num']; - } - $aCount = 0; - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if ($arg <= 0) { - return self::$_errorCodes['num']; - } - if (is_null($returnValue)) { - $returnValue = (1 / $arg); - } else { - $returnValue += (1 / $arg); - } - ++$aCount; - } - } - - // Return - if ($aCount > 0) { - return 1 / ($returnValue / $aCount); - } else { - return $returnValue; - } - } // function HARMEAN() - - - /** - * TRIMMEAN - * - * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean - * taken by excluding a percentage of data points from the top and bottom tails - * of a data set. - * - * Excel Function: - * TRIMEAN(value1[,value2[, ...]],$discard) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @param float $discard Percentage to discard - * @return float - */ - public static function TRIMMEAN() { - $aArgs = self::flattenArray(func_get_args()); - - // Calculate - $percent = array_pop($aArgs); - - if ((is_numeric($percent)) && (!is_string($percent))) { - if (($percent < 0) || ($percent > 1)) { - return self::$_errorCodes['num']; - } - $mArgs = array(); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - $discard = floor(self::COUNT($mArgs) * $percent / 2); - sort($mArgs); - for ($i=0; $i < $discard; ++$i) { - array_pop($mArgs); - array_shift($mArgs); - } - return self::AVERAGE($mArgs); - } - return self::$_errorCodes['value']; - } // function TRIMMEAN() - - - /** - * STDEV - * - * Estimates standard deviation based on a sample. The standard deviation is a measure of how - * widely values are dispersed from the average value (the mean). - * - * Excel Function: - * STDEV(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function STDEV() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - - // Return value - $returnValue = null; - - $aMean = self::AVERAGE($aArgs); - if (!is_null($aMean)) { - $aCount = -1; - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) { - $arg = (integer) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (is_null($returnValue)) { - $returnValue = pow(($arg - $aMean),2); - } else { - $returnValue += pow(($arg - $aMean),2); - } - ++$aCount; - } - } - - // Return - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - return self::$_errorCodes['divisionbyzero']; - } // function STDEV() - - - /** - * STDEVA - * - * Estimates standard deviation based on a sample, including numbers, text, and logical values - * - * Excel Function: - * STDEVA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function STDEVA() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - - // Return value - $returnValue = null; - - $aMean = self::AVERAGEA($aArgs); - if (!is_null($aMean)) { - $aCount = -1; - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - (!self::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (integer) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if (is_null($returnValue)) { - $returnValue = pow(($arg - $aMean),2); - } else { - $returnValue += pow(($arg - $aMean),2); - } - ++$aCount; - } - } - } - - // Return - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - return self::$_errorCodes['divisionbyzero']; - } // function STDEVA() - - - /** - * STDEVP - * - * Calculates standard deviation based on the entire population - * - * Excel Function: - * STDEVP(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function STDEVP() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - - // Return value - $returnValue = null; - - $aMean = self::AVERAGE($aArgs); - if (!is_null($aMean)) { - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - ((!self::isCellValue($k)) || (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE))) { - $arg = (integer) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (is_null($returnValue)) { - $returnValue = pow(($arg - $aMean),2); - } else { - $returnValue += pow(($arg - $aMean),2); - } - ++$aCount; - } - } - - // Return - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - return self::$_errorCodes['divisionbyzero']; - } // function STDEVP() - - - /** - * STDEVPA - * - * Calculates standard deviation based on the entire population, including numbers, text, and logical values - * - * Excel Function: - * STDEVPA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function STDEVPA() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - - // Return value - $returnValue = null; - - $aMean = self::AVERAGEA($aArgs); - if (!is_null($aMean)) { - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - (!self::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (integer) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if (is_null($returnValue)) { - $returnValue = pow(($arg - $aMean),2); - } else { - $returnValue += pow(($arg - $aMean),2); - } - ++$aCount; - } - } - } - - // Return - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - return self::$_errorCodes['divisionbyzero']; - } // function STDEVPA() - - - /** - * VARFunc - * - * Estimates variance based on a sample. - * - * Excel Function: - * VAR(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function VARFunc() { - // Return value - $returnValue = self::$_errorCodes['divisionbyzero']; - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - $aCount = 0; - foreach ($aArgs as $arg) { - if (is_bool($arg)) { $arg = (integer) $arg; } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - - // Return - if ($aCount > 1) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1)); - } - return $returnValue; - } // function VARFunc() - - - /** - * VARA - * - * Estimates variance based on a sample, including numbers, text, and logical values - * - * Excel Function: - * VARA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function VARA() { - // Return value - $returnValue = self::$_errorCodes['divisionbyzero']; - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = self::flattenArrayIndexed(func_get_args()); - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ((is_string($arg)) && - (self::isValue($k))) { - return self::$_errorCodes['value']; - } elseif ((is_string($arg)) && - (!self::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (integer) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - } - - // Return - if ($aCount > 1) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1)); - } - return $returnValue; - } // function VARA() - - - /** - * VARP - * - * Calculates variance based on the entire population - * - * Excel Function: - * VARP(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function VARP() { - // Return value - $returnValue = self::$_errorCodes['divisionbyzero']; - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - $aCount = 0; - foreach ($aArgs as $arg) { - if (is_bool($arg)) { $arg = (integer) $arg; } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - - // Return - if ($aCount > 0) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * $aCount); - } - return $returnValue; - } // function VARP() - - - /** - * VARPA - * - * Calculates variance based on the entire population, including numbers, text, and logical values - * - * Excel Function: - * VARPA(value1[,value2[, ...]]) - * - * @access public - * @category Statistical Functions - * @param mixed $arg,... Data values - * @return float - */ - public static function VARPA() { - // Return value - $returnValue = self::$_errorCodes['divisionbyzero']; - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = self::flattenArrayIndexed(func_get_args()); - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ((is_string($arg)) && - (self::isValue($k))) { - return self::$_errorCodes['value']; - } elseif ((is_string($arg)) && - (!self::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (integer) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - } - - // Return - if ($aCount > 0) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * $aCount); - } - return $returnValue; - } // function VARPA() - - - /** - * RANK - * - * Returns the rank of a number in a list of numbers. - * - * @param number The number whose rank you want to find. - * @param array of number An array of, or a reference to, a list of numbers. - * @param mixed Order to sort the values in the value set - * @return float - */ - public static function RANK($value,$valueSet,$order=0) { - $value = self::flattenSingleValue($value); - $valueSet = self::flattenArray($valueSet); - $order = (is_null($order)) ? 0 : (integer) self::flattenSingleValue($order); - - foreach($valueSet as $key => $valueEntry) { - if (!is_numeric($valueEntry)) { - unset($valueSet[$key]); - } - } - - if ($order == 0) { - rsort($valueSet,SORT_NUMERIC); - } else { - sort($valueSet,SORT_NUMERIC); - } - $pos = array_search($value,$valueSet); - if ($pos === False) { - return self::$_errorCodes['na']; - } - - return ++$pos; - } // function RANK() - - - /** - * PERCENTRANK - * - * Returns the rank of a value in a data set as a percentage of the data set. - * - * @param array of number An array of, or a reference to, a list of numbers. - * @param number The number whose rank you want to find. - * @param number The number of significant digits for the returned percentage value. - * @return float - */ - public static function PERCENTRANK($valueSet,$value,$significance=3) { - $valueSet = self::flattenArray($valueSet); - $value = self::flattenSingleValue($value); - $significance = (is_null($significance)) ? 3 : (integer) self::flattenSingleValue($significance); - - foreach($valueSet as $key => $valueEntry) { - if (!is_numeric($valueEntry)) { - unset($valueSet[$key]); - } - } - sort($valueSet,SORT_NUMERIC); - $valueCount = count($valueSet); - if ($valueCount == 0) { - return self::$_errorCodes['num']; - } - - $valueAdjustor = $valueCount - 1; - if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) { - return self::$_errorCodes['na']; - } - - $pos = array_search($value,$valueSet); - if ($pos === False) { - $pos = 0; - $testValue = $valueSet[0]; - while ($testValue < $value) { - $testValue = $valueSet[++$pos]; - } - --$pos; - $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos])); - } - - return round($pos / $valueAdjustor,$significance); - } // function PERCENTRANK() - - - private static function _checkTrendArrays(&$array1,&$array2) { - if (!is_array($array1)) { $array1 = array($array1); } - if (!is_array($array2)) { $array2 = array($array2); } - - $array1 = self::flattenArray($array1); - $array2 = self::flattenArray($array2); - foreach($array1 as $key => $value) { - if ((is_bool($value)) || (is_string($value)) || (is_null($value))) { - unset($array1[$key]); - unset($array2[$key]); - } - } - foreach($array2 as $key => $value) { - if ((is_bool($value)) || (is_string($value)) || (is_null($value))) { - unset($array1[$key]); - unset($array2[$key]); - } - } - $array1 = array_merge($array1); - $array2 = array_merge($array2); - - return True; - } // function _checkTrendArrays() - - - /** - * INTERCEPT - * - * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @return float - */ - public static function INTERCEPT($yValues,$xValues) { - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return self::$_errorCodes['divisionbyzero']; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); - return $bestFitLinear->getIntersect(); - } // function INTERCEPT() - - - /** - * RSQ - * - * Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @return float - */ - public static function RSQ($yValues,$xValues) { - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return self::$_errorCodes['divisionbyzero']; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); - return $bestFitLinear->getGoodnessOfFit(); - } // function RSQ() - - - /** - * SLOPE - * - * Returns the slope of the linear regression line through data points in known_y's and known_x's. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @return float - */ - public static function SLOPE($yValues,$xValues) { - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return self::$_errorCodes['divisionbyzero']; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); - return $bestFitLinear->getSlope(); - } // function SLOPE() - - - /** - * STEYX - * - * Returns the standard error of the predicted y-value for each x in the regression. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @return float - */ - public static function STEYX($yValues,$xValues) { - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return self::$_errorCodes['divisionbyzero']; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); - return $bestFitLinear->getStdevOfResiduals(); - } // function STEYX() - - - /** - * COVAR - * - * Returns covariance, the average of the products of deviations for each data point pair. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @return float - */ - public static function COVAR($yValues,$xValues) { - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return self::$_errorCodes['divisionbyzero']; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); - return $bestFitLinear->getCovariance(); - } // function COVAR() - - - /** - * CORREL - * - * Returns covariance, the average of the products of deviations for each data point pair. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @return float - */ - public static function CORREL($yValues,$xValues=null) { - if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) { - return self::$_errorCodes['value']; - } - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return self::$_errorCodes['divisionbyzero']; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); - return $bestFitLinear->getCorrelation(); - } // function CORREL() - - - /** - * LINEST - * - * Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data, - * and then returns an array that describes the line. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @param boolean A logical value specifying whether to force the intersect to equal 0. - * @param boolean A logical value specifying whether to return additional regression statistics. - * @return array - */ - public static function LINEST($yValues,$xValues=null,$const=True,$stats=False) { - $const = (is_null($const)) ? True : (boolean) self::flattenSingleValue($const); - $stats = (is_null($stats)) ? False : (boolean) self::flattenSingleValue($stats); - if (is_null($xValues)) $xValues = range(1,count(self::flattenArray($yValues))); - - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return 0; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const); - if ($stats) { - return array( array( $bestFitLinear->getSlope(), - $bestFitLinear->getSlopeSE(), - $bestFitLinear->getGoodnessOfFit(), - $bestFitLinear->getF(), - $bestFitLinear->getSSRegression(), - ), - array( $bestFitLinear->getIntersect(), - $bestFitLinear->getIntersectSE(), - $bestFitLinear->getStdevOfResiduals(), - $bestFitLinear->getDFResiduals(), - $bestFitLinear->getSSResiduals() - ) - ); - } else { - return array( $bestFitLinear->getSlope(), - $bestFitLinear->getIntersect() - ); - } - } // function LINEST() - - - /** - * LOGEST - * - * Calculates an exponential curve that best fits the X and Y data series, - * and then returns an array that describes the line. - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @param boolean A logical value specifying whether to force the intersect to equal 0. - * @param boolean A logical value specifying whether to return additional regression statistics. - * @return array - */ - public static function LOGEST($yValues,$xValues=null,$const=True,$stats=False) { - $const = (is_null($const)) ? True : (boolean) self::flattenSingleValue($const); - $stats = (is_null($stats)) ? False : (boolean) self::flattenSingleValue($stats); - if (is_null($xValues)) $xValues = range(1,count(self::flattenArray($yValues))); - - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - foreach($yValues as $value) { - if ($value <= 0.0) { - return self::$_errorCodes['num']; - } - } - - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return 1; - } - - $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const); - if ($stats) { - return array( array( $bestFitExponential->getSlope(), - $bestFitExponential->getSlopeSE(), - $bestFitExponential->getGoodnessOfFit(), - $bestFitExponential->getF(), - $bestFitExponential->getSSRegression(), - ), - array( $bestFitExponential->getIntersect(), - $bestFitExponential->getIntersectSE(), - $bestFitExponential->getStdevOfResiduals(), - $bestFitExponential->getDFResiduals(), - $bestFitExponential->getSSResiduals() - ) - ); - } else { - return array( $bestFitExponential->getSlope(), - $bestFitExponential->getIntersect() - ); - } - } // function LOGEST() - - - /** - * FORECAST - * - * Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value. - * - * @param float Value of X for which we want to find Y - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @return float - */ - public static function FORECAST($xValue,$yValues,$xValues) { - $xValue = self::flattenSingleValue($xValue); - if (!is_numeric($xValue)) { - return self::$_errorCodes['value']; - } - - if (!self::_checkTrendArrays($yValues,$xValues)) { - return self::$_errorCodes['value']; - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return self::$_errorCodes['na']; - } elseif ($yValueCount == 1) { - return self::$_errorCodes['divisionbyzero']; - } - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); - return $bestFitLinear->getValueOfYForX($xValue); - } // function FORECAST() - - - /** - * TREND - * - * Returns values along a linear trend - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @param array of mixed Values of X for which we want to find Y - * @param boolean A logical value specifying whether to force the intersect to equal 0. - * @return array of float - */ - public static function TREND($yValues,$xValues=array(),$newValues=array(),$const=True) { - $yValues = self::flattenArray($yValues); - $xValues = self::flattenArray($xValues); - $newValues = self::flattenArray($newValues); - $const = (is_null($const)) ? True : (boolean) self::flattenSingleValue($const); - - $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const); - if (count($newValues) == 0) { - $newValues = $bestFitLinear->getXValues(); - } - - $returnArray = array(); - foreach($newValues as $xValue) { - $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue); - } - - return $returnArray; - } // function TREND() - - - /** - * GROWTH - * - * Returns values along a predicted emponential trend - * - * @param array of mixed Data Series Y - * @param array of mixed Data Series X - * @param array of mixed Values of X for which we want to find Y - * @param boolean A logical value specifying whether to force the intersect to equal 0. - * @return array of float - */ - public static function GROWTH($yValues,$xValues=array(),$newValues=array(),$const=True) { - $yValues = self::flattenArray($yValues); - $xValues = self::flattenArray($xValues); - $newValues = self::flattenArray($newValues); - $const = (is_null($const)) ? True : (boolean) self::flattenSingleValue($const); - - $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const); - if (count($newValues) == 0) { - $newValues = $bestFitExponential->getXValues(); - } - - $returnArray = array(); - foreach($newValues as $xValue) { - $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue); - } - - return $returnArray; - } // function GROWTH() - - - private static function _romanCut($num, $n) { - return ($num - ($num % $n ) ) / $n; - } // function _romanCut() - - - public static function ROMAN($aValue, $style=0) { - $aValue = (integer) self::flattenSingleValue($aValue); - $style = (is_null($style)) ? 0 : (integer) self::flattenSingleValue($style); - if ((!is_numeric($aValue)) || ($aValue < 0) || ($aValue >= 4000)) { - return self::$_errorCodes['value']; - } - if ($aValue == 0) { - return ''; - } - - $mill = Array('', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM'); - $cent = Array('', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'); - $tens = Array('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'); - $ones = Array('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'); - - $roman = ''; - while ($aValue > 5999) { - $roman .= 'M'; - $aValue -= 1000; - } - $m = self::_romanCut($aValue, 1000); $aValue %= 1000; - $c = self::_romanCut($aValue, 100); $aValue %= 100; - $t = self::_romanCut($aValue, 10); $aValue %= 10; - - return $roman.$mill[$m].$cent[$c].$tens[$t].$ones[$aValue]; - } // function ROMAN() - - - /** - * SUBTOTAL - * - * Returns a subtotal in a list or database. - * - * @param int the number 1 to 11 that specifies which function to - * use in calculating subtotals within a list. - * @param array of mixed Data Series - * @return float - */ - public static function SUBTOTAL() { - $aArgs = self::flattenArray(func_get_args()); - - // Calculate - $subtotal = array_shift($aArgs); - - if ((is_numeric($subtotal)) && (!is_string($subtotal))) { - switch($subtotal) { - case 1 : - return self::AVERAGE($aArgs); - break; - case 2 : - return self::COUNT($aArgs); - break; - case 3 : - return self::COUNTA($aArgs); - break; - case 4 : - return self::MAX($aArgs); - break; - case 5 : - return self::MIN($aArgs); - break; - case 6 : - return self::PRODUCT($aArgs); - break; - case 7 : - return self::STDEV($aArgs); - break; - case 8 : - return self::STDEVP($aArgs); - break; - case 9 : - return self::SUM($aArgs); - break; - case 10 : - return self::VARFunc($aArgs); - break; - case 11 : - return self::VARP($aArgs); - break; - } - } - return self::$_errorCodes['value']; - } // function SUBTOTAL() - - - /** - * SQRTPI - * - * Returns the square root of (number * pi). - * - * @param float $number Number - * @return float Square Root of Number * Pi - */ - public static function SQRTPI($number) { - $number = self::flattenSingleValue($number); - - if (is_numeric($number)) { - if ($number < 0) { - return self::$_errorCodes['num']; - } - return sqrt($number * M_PI) ; - } - return self::$_errorCodes['value']; - } // function SQRTPI() - - - /** - * FACT - * - * Returns the factorial of a number. - * - * @param float $factVal Factorial Value - * @return int Factorial - */ - public static function FACT($factVal) { - $factVal = self::flattenSingleValue($factVal); - - if (is_numeric($factVal)) { - if ($factVal < 0) { - return self::$_errorCodes['num']; - } - $factLoop = floor($factVal); - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - if ($factVal > $factLoop) { - return self::$_errorCodes['num']; - } - } - - $factorial = 1; - while ($factLoop > 1) { - $factorial *= $factLoop--; - } - return $factorial ; - } - return self::$_errorCodes['value']; - } // function FACT() - - - /** - * FACTDOUBLE - * - * Returns the double factorial of a number. - * - * @param float $factVal Factorial Value - * @return int Double Factorial - */ - public static function FACTDOUBLE($factVal) { - $factLoop = floor(self::flattenSingleValue($factVal)); - - if (is_numeric($factLoop)) { - if ($factVal < 0) { - return self::$_errorCodes['num']; - } - $factorial = 1; - while ($factLoop > 1) { - $factorial *= $factLoop--; - --$factLoop; - } - return $factorial ; - } - return self::$_errorCodes['value']; - } // function FACTDOUBLE() - - - /** - * MULTINOMIAL - * - * Returns the ratio of the factorial of a sum of values to the product of factorials. - * - * @param array of mixed Data Series - * @return float - */ - public static function MULTINOMIAL() { - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - $summer = 0; - $divisor = 1; - foreach ($aArgs as $arg) { - // Is it a numeric value? - if (is_numeric($arg)) { - if ($arg < 1) { - return self::$_errorCodes['num']; - } - $summer += floor($arg); - $divisor *= self::FACT($arg); - } else { - return self::$_errorCodes['value']; - } - } - - // Return - if ($summer > 0) { - $summer = self::FACT($summer); - return $summer / $divisor; - } - return 0; - } // function MULTINOMIAL() - - - /** - * CEILING - * - * Returns number rounded up, away from zero, to the nearest multiple of significance. - * - * @param float $number Number to round - * @param float $significance Significance - * @return float Rounded Number - */ - public static function CEILING($number,$significance=null) { - $number = self::flattenSingleValue($number); - $significance = self::flattenSingleValue($significance); - - if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) { - $significance = $number/abs($number); - } - - if ((is_numeric($number)) && (is_numeric($significance))) { - if (self::SIGN($number) == self::SIGN($significance)) { - if ($significance == 0.0) { - return 0; - } - return ceil($number / $significance) * $significance; - } else { - return self::$_errorCodes['num']; - } - } - return self::$_errorCodes['value']; - } // function CEILING() - - - /** - * EVEN - * - * Returns number rounded up to the nearest even integer. - * - * @param float $number Number to round - * @return int Rounded Number - */ - public static function EVEN($number) { - $number = self::flattenSingleValue($number); - - if (is_numeric($number)) { - $significance = 2 * self::SIGN($number); - return self::CEILING($number,$significance); - } - return self::$_errorCodes['value']; - } // function EVEN() - - - /** - * ODD - * - * Returns number rounded up to the nearest odd integer. - * - * @param float $number Number to round - * @return int Rounded Number - */ - public static function ODD($number) { - $number = self::flattenSingleValue($number); - - if (is_numeric($number)) { - $significance = self::SIGN($number); - if ($significance == 0) { - return 1; - } - $result = self::CEILING($number,$significance); - if (self::IS_EVEN($result)) { - $result += $significance; - } - return $result; - } - return self::$_errorCodes['value']; - } // function ODD() - - - /** - * INTVALUE - * - * Casts a floating point value to an integer - * - * @param float $number Number to cast to an integer - * @return integer Integer value - */ - public static function INTVALUE($number) { - $number = self::flattenSingleValue($number); - - if (is_numeric($number)) { - return (int) floor($number); - } - return self::$_errorCodes['value']; - } // function INTVALUE() - - - /** - * ROUNDUP - * - * Rounds a number up to a specified number of decimal places - * - * @param float $number Number to round - * @param int $digits Number of digits to which you want to round $number - * @return float Rounded Number - */ - public static function ROUNDUP($number,$digits) { - $number = self::flattenSingleValue($number); - $digits = self::flattenSingleValue($digits); - - if ((is_numeric($number)) && (is_numeric($digits))) { - $significance = pow(10,$digits); - if ($number < 0.0) { - return floor($number * $significance) / $significance; - } else { - return ceil($number * $significance) / $significance; - } - } - return self::$_errorCodes['value']; - } // function ROUNDUP() - - - /** - * ROUNDDOWN - * - * Rounds a number down to a specified number of decimal places - * - * @param float $number Number to round - * @param int $digits Number of digits to which you want to round $number - * @return float Rounded Number - */ - public static function ROUNDDOWN($number,$digits) { - $number = self::flattenSingleValue($number); - $digits = self::flattenSingleValue($digits); - - if ((is_numeric($number)) && (is_numeric($digits))) { - $significance = pow(10,$digits); - if ($number < 0.0) { - return ceil($number * $significance) / $significance; - } else { - return floor($number * $significance) / $significance; - } - } - return self::$_errorCodes['value']; - } // function ROUNDDOWN() - - - /** - * MROUND - * - * Rounds a number to the nearest multiple of a specified value - * - * @param float $number Number to round - * @param int $multiple Multiple to which you want to round $number - * @return float Rounded Number - */ - public static function MROUND($number,$multiple) { - $number = self::flattenSingleValue($number); - $multiple = self::flattenSingleValue($multiple); - - if ((is_numeric($number)) && (is_numeric($multiple))) { - if ($multiple == 0) { - return 0; - } - if ((self::SIGN($number)) == (self::SIGN($multiple))) { - $multiplier = 1 / $multiple; - return round($number * $multiplier) / $multiplier; - } - return self::$_errorCodes['num']; - } - return self::$_errorCodes['value']; - } // function MROUND() - - - /** - * SIGN - * - * Determines the sign of a number. Returns 1 if the number is positive, zero (0) - * if the number is 0, and -1 if the number is negative. - * - * @param float $number Number to round - * @return int sign value - */ - public static function SIGN($number) { - $number = self::flattenSingleValue($number); - - if (is_numeric($number)) { - if ($number == 0.0) { - return 0; - } - return $number / abs($number); - } - return self::$_errorCodes['value']; - } // function SIGN() - - - /** - * FLOOR - * - * Rounds number down, toward zero, to the nearest multiple of significance. - * - * @param float $number Number to round - * @param float $significance Significance - * @return float Rounded Number - */ - public static function FLOOR($number,$significance=null) { - $number = self::flattenSingleValue($number); - $significance = self::flattenSingleValue($significance); - - if ((is_null($significance)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) { - $significance = $number/abs($number); - } - - if ((is_numeric($number)) && (is_numeric($significance))) { - if ((float) $significance == 0.0) { - return self::$_errorCodes['divisionbyzero']; - } - if (self::SIGN($number) == self::SIGN($significance)) { - return floor($number / $significance) * $significance; - } else { - return self::$_errorCodes['num']; - } - } - return self::$_errorCodes['value']; - } // function FLOOR() - - - /** - * PERMUT - * - * Returns the number of permutations for a given number of objects that can be - * selected from number objects. A permutation is any set or subset of objects or - * events where internal order is significant. Permutations are different from - * combinations, for which the internal order is not significant. Use this function - * for lottery-style probability calculations. - * - * @param int $numObjs Number of different objects - * @param int $numInSet Number of objects in each permutation - * @return int Number of permutations - */ - public static function PERMUT($numObjs,$numInSet) { - $numObjs = self::flattenSingleValue($numObjs); - $numInSet = self::flattenSingleValue($numInSet); - - if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { - $numInSet = floor($numInSet); - if ($numObjs < $numInSet) { - return self::$_errorCodes['num']; - } - return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)); - } - return self::$_errorCodes['value']; - } // function PERMUT() - - - /** - * COMBIN - * - * Returns the number of combinations for a given number of items. Use COMBIN to - * determine the total possible number of groups for a given number of items. - * - * @param int $numObjs Number of different objects - * @param int $numInSet Number of objects in each combination - * @return int Number of combinations - */ - public static function COMBIN($numObjs,$numInSet) { - $numObjs = self::flattenSingleValue($numObjs); - $numInSet = self::flattenSingleValue($numInSet); - - if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { - if ($numObjs < $numInSet) { - return self::$_errorCodes['num']; - } elseif ($numInSet < 0) { - return self::$_errorCodes['num']; - } - return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet); - } - return self::$_errorCodes['value']; - } // function COMBIN() - - - /** - * SERIESSUM - * - * Returns the sum of a power series - * - * @param float $x Input value to the power series - * @param float $n Initial power to which you want to raise $x - * @param float $m Step by which to increase $n for each term in the series - * @param array of mixed Data Series - * @return float - */ - public static function SERIESSUM() { - // Return value - $returnValue = 0; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - - $x = array_shift($aArgs); - $n = array_shift($aArgs); - $m = array_shift($aArgs); - - if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) { - // Calculate - $i = 0; - foreach($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += $arg * pow($x,$n + ($m * $i++)); - } else { - return self::$_errorCodes['value']; - } - } - // Return - return $returnValue; - } - return self::$_errorCodes['value']; - } // function SERIESSUM() - - - /** - * STANDARDIZE - * - * Returns a normalized value from a distribution characterized by mean and standard_dev. - * - * @param float $value Value to normalize - * @param float $mean Mean Value - * @param float $stdDev Standard Deviation - * @return float Standardized value - */ - public static function STANDARDIZE($value,$mean,$stdDev) { - $value = self::flattenSingleValue($value); - $mean = self::flattenSingleValue($mean); - $stdDev = self::flattenSingleValue($stdDev); - - if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if ($stdDev <= 0) { - return self::$_errorCodes['num']; - } - return ($value - $mean) / $stdDev ; - } - return self::$_errorCodes['value']; - } // function STANDARDIZE() - - - // - // Private method to return an array of the factors of the input value - // - private static function _factors($value) { - $startVal = floor(sqrt($value)); - - $factorArray = array(); - for ($i = $startVal; $i > 1; --$i) { - if (($value % $i) == 0) { - $factorArray = array_merge($factorArray,self::_factors($value / $i)); - $factorArray = array_merge($factorArray,self::_factors($i)); - if ($i <= sqrt($value)) { - break; - } - } - } - if (count($factorArray) > 0) { - rsort($factorArray); - return $factorArray; - } else { - return array((integer) $value); - } - } // function _factors() - - - /** - * LCM - * - * Returns the lowest common multiplier of a series of numbers - * - * @param $array Values to calculate the Lowest Common Multiplier - * @return int Lowest Common Multiplier - */ - public static function LCM() { - $aArgs = self::flattenArray(func_get_args()); - - $returnValue = 1; - $allPoweredFactors = array(); - foreach($aArgs as $value) { - if (!is_numeric($value)) { - return self::$_errorCodes['value']; - } - if ($value == 0) { - return 0; - } elseif ($value < 0) { - return self::$_errorCodes['num']; - } - $myFactors = self::_factors(floor($value)); - $myCountedFactors = array_count_values($myFactors); - $myPoweredFactors = array(); - foreach($myCountedFactors as $myCountedFactor => $myCountedPower) { - $myPoweredFactors[$myCountedFactor] = pow($myCountedFactor,$myCountedPower); - } - foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor) { - if (array_key_exists($myPoweredValue,$allPoweredFactors)) { - if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) { - $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; - } - } else { - $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; - } - } - } - foreach($allPoweredFactors as $allPoweredFactor) { - $returnValue *= (integer) $allPoweredFactor; - } - return $returnValue; - } // function LCM() - - - /** - * GCD - * - * Returns the greatest common divisor of a series of numbers - * - * @param $array Values to calculate the Greatest Common Divisor - * @return int Greatest Common Divisor - */ - public static function GCD() { - $aArgs = self::flattenArray(func_get_args()); - - $returnValue = 1; - $allPoweredFactors = array(); - foreach($aArgs as $value) { - if ($value == 0) { - break; - } - $myFactors = self::_factors($value); - $myCountedFactors = array_count_values($myFactors); - $allValuesFactors[] = $myCountedFactors; - } - $allValuesCount = count($allValuesFactors); - $mergedArray = $allValuesFactors[0]; - for ($i=1;$i < $allValuesCount; ++$i) { - $mergedArray = array_intersect_key($mergedArray,$allValuesFactors[$i]); - } - $mergedArrayValues = count($mergedArray); - if ($mergedArrayValues == 0) { - return $returnValue; - } elseif ($mergedArrayValues > 1) { - foreach($mergedArray as $mergedKey => $mergedValue) { - foreach($allValuesFactors as $highestPowerTest) { - foreach($highestPowerTest as $testKey => $testValue) { - if (($testKey == $mergedKey) && ($testValue < $mergedValue)) { - $mergedArray[$mergedKey] = $testValue; - $mergedValue = $testValue; - } - } - } - } - - $returnValue = 1; - foreach($mergedArray as $key => $value) { - $returnValue *= pow($key,$value); - } - return $returnValue; - } else { - $keys = array_keys($mergedArray); - $key = $keys[0]; - $value = $mergedArray[$key]; - foreach($allValuesFactors as $testValue) { - foreach($testValue as $mergedKey => $mergedValue) { - if (($mergedKey == $key) && ($mergedValue < $value)) { - $value = $mergedValue; - } - } - } - return pow($key,$value); - } - } // function GCD() - - - /** - * BINOMDIST - * - * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with - * a fixed number of tests or trials, when the outcomes of any trial are only success or failure, - * when trials are independent, and when the probability of success is constant throughout the - * experiment. For example, BINOMDIST can calculate the probability that two of the next three - * babies born are male. - * - * @param float $value Number of successes in trials - * @param float $trials Number of trials - * @param float $probability Probability of success on each trial - * @param boolean $cumulative - * @return float - * - * @todo Cumulative distribution function - * - */ - public static function BINOMDIST($value, $trials, $probability, $cumulative) { - $value = floor(self::flattenSingleValue($value)); - $trials = floor(self::flattenSingleValue($trials)); - $probability = self::flattenSingleValue($probability); - - if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) { - if (($value < 0) || ($value > $trials)) { - return self::$_errorCodes['num']; - } - if (($probability < 0) || ($probability > 1)) { - return self::$_errorCodes['num']; - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - $summer = 0; - for ($i = 0; $i <= $value; ++$i) { - $summer += self::COMBIN($trials,$i) * pow($probability,$i) * pow(1 - $probability,$trials - $i); - } - return $summer; - } else { - return self::COMBIN($trials,$value) * pow($probability,$value) * pow(1 - $probability,$trials - $value) ; - } - } - } - return self::$_errorCodes['value']; - } // function BINOMDIST() - - - /** - * NEGBINOMDIST - * - * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that - * there will be number_f failures before the number_s-th success, when the constant - * probability of a success is probability_s. This function is similar to the binomial - * distribution, except that the number of successes is fixed, and the number of trials is - * variable. Like the binomial, trials are assumed to be independent. - * - * @param float $failures Number of Failures - * @param float $successes Threshold number of Successes - * @param float $probability Probability of success on each trial - * @return float - * - */ - public static function NEGBINOMDIST($failures, $successes, $probability) { - $failures = floor(self::flattenSingleValue($failures)); - $successes = floor(self::flattenSingleValue($successes)); - $probability = self::flattenSingleValue($probability); - - if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) { - if (($failures < 0) || ($successes < 1)) { - return self::$_errorCodes['num']; - } - if (($probability < 0) || ($probability > 1)) { - return self::$_errorCodes['num']; - } - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - if (($failures + $successes - 1) <= 0) { - return self::$_errorCodes['num']; - } - } - return (self::COMBIN($failures + $successes - 1,$successes - 1)) * (pow($probability,$successes)) * (pow(1 - $probability,$failures)) ; - } - return self::$_errorCodes['value']; - } // function NEGBINOMDIST() - - - /** - * CRITBINOM - * - * Returns the smallest value for which the cumulative binomial distribution is greater - * than or equal to a criterion value - * - * See http://support.microsoft.com/kb/828117/ for details of the algorithm used - * - * @param float $trials number of Bernoulli trials - * @param float $probability probability of a success on each trial - * @param float $alpha criterion value - * @return int - * - * @todo Warning. This implementation differs from the algorithm detailed on the MS - * web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess - * This eliminates a potential endless loop error, but may have an adverse affect on the - * accuracy of the function (although all my tests have so far returned correct results). - * - */ - public static function CRITBINOM($trials, $probability, $alpha) { - $trials = floor(self::flattenSingleValue($trials)); - $probability = self::flattenSingleValue($probability); - $alpha = self::flattenSingleValue($alpha); - - if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) { - if ($trials < 0) { - return self::$_errorCodes['num']; - } - if (($probability < 0) || ($probability > 1)) { - return self::$_errorCodes['num']; - } - if (($alpha < 0) || ($alpha > 1)) { - return self::$_errorCodes['num']; - } - if ($alpha <= 0.5) { - $t = sqrt(log(1 / ($alpha * $alpha))); - $trialsApprox = 0 - ($t + (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t)); - } else { - $t = sqrt(log(1 / pow(1 - $alpha,2))); - $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t); - } - $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability))); - if ($Guess < 0) { - $Guess = 0; - } elseif ($Guess > $trials) { - $Guess = $trials; - } - - $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0; - $EssentiallyZero = 10e-12; - - $m = floor($trials * $probability); - ++$TotalUnscaledProbability; - if ($m == $Guess) { ++$UnscaledPGuess; } - if ($m <= $Guess) { ++$UnscaledCumPGuess; } - - $PreviousValue = 1; - $Done = False; - $k = $m + 1; - while ((!$Done) && ($k <= $trials)) { - $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability)); - $TotalUnscaledProbability += $CurrentValue; - if ($k == $Guess) { $UnscaledPGuess += $CurrentValue; } - if ($k <= $Guess) { $UnscaledCumPGuess += $CurrentValue; } - if ($CurrentValue <= $EssentiallyZero) { $Done = True; } - $PreviousValue = $CurrentValue; - ++$k; - } - - $PreviousValue = 1; - $Done = False; - $k = $m - 1; - while ((!$Done) && ($k >= 0)) { - $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability); - $TotalUnscaledProbability += $CurrentValue; - if ($k == $Guess) { $UnscaledPGuess += $CurrentValue; } - if ($k <= $Guess) { $UnscaledCumPGuess += $CurrentValue; } - if ($CurrentValue <= $EssentiallyZero) { $Done = True; } - $PreviousValue = $CurrentValue; - --$k; - } - - $PGuess = $UnscaledPGuess / $TotalUnscaledProbability; - $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability; - -// $CumPGuessMinus1 = $CumPGuess - $PGuess; - $CumPGuessMinus1 = $CumPGuess - 1; - - while (True) { - if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) { - return $Guess; - } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) { - $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability); - $CumPGuessMinus1 = $CumPGuess; - $CumPGuess = $CumPGuess + $PGuessPlus1; - $PGuess = $PGuessPlus1; - ++$Guess; - } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) { - $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability; - $CumPGuess = $CumPGuessMinus1; - $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess; - $PGuess = $PGuessMinus1; - --$Guess; - } - } - } - return self::$_errorCodes['value']; - } // function CRITBINOM() - - - /** - * CHIDIST - * - * Returns the one-tailed probability of the chi-squared distribution. - * - * @param float $value Value for the function - * @param float $degrees degrees of freedom - * @return float - */ - public static function CHIDIST($value, $degrees) { - $value = self::flattenSingleValue($value); - $degrees = floor(self::flattenSingleValue($degrees)); - - if ((is_numeric($value)) && (is_numeric($degrees))) { - if ($degrees < 1) { - return self::$_errorCodes['num']; - } - if ($value < 0) { - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - return 1; - } - return self::$_errorCodes['num']; - } - return 1 - (self::_incompleteGamma($degrees/2,$value/2) / self::_gamma($degrees/2)); - } - return self::$_errorCodes['value']; - } // function CHIDIST() - - - /** - * CHIINV - * - * Returns the one-tailed probability of the chi-squared distribution. - * - * @param float $probability Probability for the function - * @param float $degrees degrees of freedom - * @return float - */ - public static function CHIINV($probability, $degrees) { - $probability = self::flattenSingleValue($probability); - $degrees = floor(self::flattenSingleValue($degrees)); - - if ((is_numeric($probability)) && (is_numeric($degrees))) { - - $xLo = 100; - $xHi = 0; - - $x = $xNew = 1; - $dx = 1; - $i = 0; - - while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { - // Apply Newton-Raphson step - $result = self::CHIDIST($x, $degrees); - $error = $result - $probability; - if ($error == 0.0) { - $dx = 0; - } elseif ($error < 0.0) { - $xLo = $x; - } else { - $xHi = $x; - } - // Avoid division by zero - if ($result != 0.0) { - $dx = $error / $result; - $xNew = $x - $dx; - } - // If the NR fails to converge (which for example may be the - // case if the initial guess is too rough) we apply a bisection - // step to determine a more narrow interval around the root. - if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { - $xNew = ($xLo + $xHi) / 2; - $dx = $xNew - $x; - } - $x = $xNew; - } - if ($i == MAX_ITERATIONS) { - return self::$_errorCodes['na']; - } - return round($x,12); - } - return self::$_errorCodes['value']; - } // function CHIINV() - - - /** - * EXPONDIST - * - * Returns the exponential distribution. Use EXPONDIST to model the time between events, - * such as how long an automated bank teller takes to deliver cash. For example, you can - * use EXPONDIST to determine the probability that the process takes at most 1 minute. - * - * @param float $value Value of the function - * @param float $lambda The parameter value - * @param boolean $cumulative - * @return float - */ - public static function EXPONDIST($value, $lambda, $cumulative) { - $value = self::flattenSingleValue($value); - $lambda = self::flattenSingleValue($lambda); - $cumulative = self::flattenSingleValue($cumulative); - - if ((is_numeric($value)) && (is_numeric($lambda))) { - if (($value < 0) || ($lambda < 0)) { - return self::$_errorCodes['num']; - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return 1 - exp(0-$value*$lambda); - } else { - return $lambda * exp(0-$value*$lambda); - } - } - } - return self::$_errorCodes['value']; - } // function EXPONDIST() - - - /** - * FISHER - * - * Returns the Fisher transformation at x. This transformation produces a function that - * is normally distributed rather than skewed. Use this function to perform hypothesis - * testing on the correlation coefficient. - * - * @param float $value - * @return float - */ - public static function FISHER($value) { - $value = self::flattenSingleValue($value); - - if (is_numeric($value)) { - if (($value <= -1) || ($value >= 1)) { - return self::$_errorCodes['num']; - } - return 0.5 * log((1+$value)/(1-$value)); - } - return self::$_errorCodes['value']; - } // function FISHER() - - - /** - * FISHERINV - * - * Returns the inverse of the Fisher transformation. Use this transformation when - * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then - * FISHERINV(y) = x. - * - * @param float $value - * @return float - */ - public static function FISHERINV($value) { - $value = self::flattenSingleValue($value); - - if (is_numeric($value)) { - return (exp(2 * $value) - 1) / (exp(2 * $value) + 1); - } - return self::$_errorCodes['value']; - } // function FISHERINV() - - - // Function cache for _logBeta function - private static $_logBetaCache_p = 0.0; - private static $_logBetaCache_q = 0.0; - private static $_logBetaCache_result = 0.0; - - /** - * The natural logarithm of the beta function. - * @param p require p>0 - * @param q require q>0 - * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow - * @author Jaco van Kooten - */ - private static function _logBeta($p, $q) { - if ($p != self::$_logBetaCache_p || $q != self::$_logBetaCache_q) { - self::$_logBetaCache_p = $p; - self::$_logBetaCache_q = $q; - if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) { - self::$_logBetaCache_result = 0.0; - } else { - self::$_logBetaCache_result = self::_logGamma($p) + self::_logGamma($q) - self::_logGamma($p + $q); - } - } - return self::$_logBetaCache_result; - } // function _logBeta() - - - /** - * Evaluates of continued fraction part of incomplete beta function. - * Based on an idea from Numerical Recipes (W.H. Press et al, 1992). - * @author Jaco van Kooten - */ - private static function _betaFraction($x, $p, $q) { - $c = 1.0; - $sum_pq = $p + $q; - $p_plus = $p + 1.0; - $p_minus = $p - 1.0; - $h = 1.0 - $sum_pq * $x / $p_plus; - if (abs($h) < XMININ) { - $h = XMININ; - } - $h = 1.0 / $h; - $frac = $h; - $m = 1; - $delta = 0.0; - while ($m <= MAX_ITERATIONS && abs($delta-1.0) > PRECISION ) { - $m2 = 2 * $m; - // even index for d - $d = $m * ($q - $m) * $x / ( ($p_minus + $m2) * ($p + $m2)); - $h = 1.0 + $d * $h; - if (abs($h) < XMININ) { - $h = XMININ; - } - $h = 1.0 / $h; - $c = 1.0 + $d / $c; - if (abs($c) < XMININ) { - $c = XMININ; - } - $frac *= $h * $c; - // odd index for d - $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2)); - $h = 1.0 + $d * $h; - if (abs($h) < XMININ) { - $h = XMININ; - } - $h = 1.0 / $h; - $c = 1.0 + $d / $c; - if (abs($c) < XMININ) { - $c = XMININ; - } - $delta = $h * $c; - $frac *= $delta; - ++$m; - } - return $frac; - } // function _betaFraction() - - - /** - * logGamma function - * - * @version 1.1 - * @author Jaco van Kooten - * - * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher. - * - * The natural logarithm of the gamma function.
- * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz
- * Applied Mathematics Division
- * Argonne National Laboratory
- * Argonne, IL 60439
- *

- * References: - *

    - *
  1. W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural - * Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.
  2. - *
  3. K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.
  4. - *
  5. Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.
  6. - *
- *

- *

- * From the original documentation: - *

- *

- * This routine calculates the LOG(GAMMA) function for a positive real argument X. - * Computation is based on an algorithm outlined in references 1 and 2. - * The program uses rational functions that theoretically approximate LOG(GAMMA) - * to at least 18 significant decimal digits. The approximation for X > 12 is from - * reference 3, while approximations for X < 12.0 are similar to those in reference - * 1, but are unpublished. The accuracy achieved depends on the arithmetic system, - * the compiler, the intrinsic functions, and proper selection of the - * machine-dependent constants. - *

- *

- * Error returns:
- * The program returns the value XINF for X .LE. 0.0 or when overflow would occur. - * The computation is believed to be free of underflow and overflow. - *

- * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305 - */ - - // Function cache for logGamma - private static $_logGammaCache_result = 0.0; - private static $_logGammaCache_x = 0.0; - - private static function _logGamma($x) { - // Log Gamma related constants - static $lg_d1 = -0.5772156649015328605195174; - static $lg_d2 = 0.4227843350984671393993777; - static $lg_d4 = 1.791759469228055000094023; - - static $lg_p1 = array( 4.945235359296727046734888, - 201.8112620856775083915565, - 2290.838373831346393026739, - 11319.67205903380828685045, - 28557.24635671635335736389, - 38484.96228443793359990269, - 26377.48787624195437963534, - 7225.813979700288197698961 ); - static $lg_p2 = array( 4.974607845568932035012064, - 542.4138599891070494101986, - 15506.93864978364947665077, - 184793.2904445632425417223, - 1088204.76946882876749847, - 3338152.967987029735917223, - 5106661.678927352456275255, - 3074109.054850539556250927 ); - static $lg_p4 = array( 14745.02166059939948905062, - 2426813.369486704502836312, - 121475557.4045093227939592, - 2663432449.630976949898078, - 29403789566.34553899906876, - 170266573776.5398868392998, - 492612579337.743088758812, - 560625185622.3951465078242 ); - - static $lg_q1 = array( 67.48212550303777196073036, - 1113.332393857199323513008, - 7738.757056935398733233834, - 27639.87074403340708898585, - 54993.10206226157329794414, - 61611.22180066002127833352, - 36351.27591501940507276287, - 8785.536302431013170870835 ); - static $lg_q2 = array( 183.0328399370592604055942, - 7765.049321445005871323047, - 133190.3827966074194402448, - 1136705.821321969608938755, - 5267964.117437946917577538, - 13467014.54311101692290052, - 17827365.30353274213975932, - 9533095.591844353613395747 ); - static $lg_q4 = array( 2690.530175870899333379843, - 639388.5654300092398984238, - 41355999.30241388052042842, - 1120872109.61614794137657, - 14886137286.78813811542398, - 101680358627.2438228077304, - 341747634550.7377132798597, - 446315818741.9713286462081 ); - - static $lg_c = array( -0.001910444077728, - 8.4171387781295e-4, - -5.952379913043012e-4, - 7.93650793500350248e-4, - -0.002777777777777681622553, - 0.08333333333333333331554247, - 0.0057083835261 ); - - // Rough estimate of the fourth root of logGamma_xBig - static $lg_frtbig = 2.25e76; - static $pnt68 = 0.6796875; - - - if ($x == self::$_logGammaCache_x) { - return self::$_logGammaCache_result; - } - $y = $x; - if ($y > 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE) { - if ($y <= EPS) { - $res = -log(y); - } elseif ($y <= 1.5) { - // --------------------- - // EPS .LT. X .LE. 1.5 - // --------------------- - if ($y < $pnt68) { - $corr = -log($y); - $xm1 = $y; - } else { - $corr = 0.0; - $xm1 = $y - 1.0; - } - if ($y <= 0.5 || $y >= $pnt68) { - $xden = 1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm1 + $lg_p1[$i]; - $xden = $xden * $xm1 + $lg_q1[$i]; - } - $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden)); - } else { - $xm2 = $y - 1.0; - $xden = 1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm2 + $lg_p2[$i]; - $xden = $xden * $xm2 + $lg_q2[$i]; - } - $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden)); - } - } elseif ($y <= 4.0) { - // --------------------- - // 1.5 .LT. X .LE. 4.0 - // --------------------- - $xm2 = $y - 2.0; - $xden = 1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm2 + $lg_p2[$i]; - $xden = $xden * $xm2 + $lg_q2[$i]; - } - $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden)); - } elseif ($y <= 12.0) { - // ---------------------- - // 4.0 .LT. X .LE. 12.0 - // ---------------------- - $xm4 = $y - 4.0; - $xden = -1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm4 + $lg_p4[$i]; - $xden = $xden * $xm4 + $lg_q4[$i]; - } - $res = $lg_d4 + $xm4 * ($xnum / $xden); - } else { - // --------------------------------- - // Evaluate for argument .GE. 12.0 - // --------------------------------- - $res = 0.0; - if ($y <= $lg_frtbig) { - $res = $lg_c[6]; - $ysq = $y * $y; - for ($i = 0; $i < 6; ++$i) - $res = $res / $ysq + $lg_c[$i]; - } - $res /= $y; - $corr = log($y); - $res = $res + log(SQRT2PI) - 0.5 * $corr; - $res += $y * ($corr - 1.0); - } - } else { - // -------------------------- - // Return for bad arguments - // -------------------------- - $res = MAX_VALUE; - } - // ------------------------------ - // Final adjustments and return - // ------------------------------ - self::$_logGammaCache_x = $x; - self::$_logGammaCache_result = $res; - return $res; - } // function _logGamma() - - - /** - * Beta function. - * - * @author Jaco van Kooten - * - * @param p require p>0 - * @param q require q>0 - * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow - */ - private static function _beta($p, $q) { - if ($p <= 0.0 || $q <= 0.0 || ($p + $q) > LOG_GAMMA_X_MAX_VALUE) { - return 0.0; - } else { - return exp(self::_logBeta($p, $q)); - } - } // function _beta() - - - /** - * Incomplete beta function - * - * @author Jaco van Kooten - * @author Paul Meagher - * - * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992). - * @param x require 0<=x<=1 - * @param p require p>0 - * @param q require q>0 - * @return 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow - */ - private static function _incompleteBeta($x, $p, $q) { - if ($x <= 0.0) { - return 0.0; - } elseif ($x >= 1.0) { - return 1.0; - } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) { - return 0.0; - } - $beta_gam = exp((0 - self::_logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x)); - if ($x < ($p + 1.0) / ($p + $q + 2.0)) { - return $beta_gam * self::_betaFraction($x, $p, $q) / $p; - } else { - return 1.0 - ($beta_gam * self::_betaFraction(1 - $x, $q, $p) / $q); - } - } // function _incompleteBeta() - - - /** - * BETADIST - * - * Returns the beta distribution. - * - * @param float $value Value at which you want to evaluate the distribution - * @param float $alpha Parameter to the distribution - * @param float $beta Parameter to the distribution - * @param boolean $cumulative - * @return float - * - */ - public static function BETADIST($value,$alpha,$beta,$rMin=0,$rMax=1) { - $value = self::flattenSingleValue($value); - $alpha = self::flattenSingleValue($alpha); - $beta = self::flattenSingleValue($beta); - $rMin = self::flattenSingleValue($rMin); - $rMax = self::flattenSingleValue($rMax); - - if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { - if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) { - return self::$_errorCodes['num']; - } - if ($rMin > $rMax) { - $tmp = $rMin; - $rMin = $rMax; - $rMax = $tmp; - } - $value -= $rMin; - $value /= ($rMax - $rMin); - return self::_incompleteBeta($value,$alpha,$beta); - } - return self::$_errorCodes['value']; - } // function BETADIST() - - - /** - * BETAINV - * - * Returns the inverse of the beta distribution. - * - * @param float $probability Probability at which you want to evaluate the distribution - * @param float $alpha Parameter to the distribution - * @param float $beta Parameter to the distribution - * @param boolean $cumulative - * @return float - * - */ - public static function BETAINV($probability,$alpha,$beta,$rMin=0,$rMax=1) { - $probability = self::flattenSingleValue($probability); - $alpha = self::flattenSingleValue($alpha); - $beta = self::flattenSingleValue($beta); - $rMin = self::flattenSingleValue($rMin); - $rMax = self::flattenSingleValue($rMax); - - if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { - if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) { - return self::$_errorCodes['num']; - } - if ($rMin > $rMax) { - $tmp = $rMin; - $rMin = $rMax; - $rMax = $tmp; - } - $a = 0; - $b = 2; - - $i = 0; - while ((($b - $a) > PRECISION) && ($i++ < MAX_ITERATIONS)) { - $guess = ($a + $b) / 2; - $result = self::BETADIST($guess, $alpha, $beta); - if (($result == $probability) || ($result == 0)) { - $b = $a; - } elseif ($result > $probability) { - $b = $guess; - } else { - $a = $guess; - } - } - if ($i == MAX_ITERATIONS) { - return self::$_errorCodes['na']; - } - return round($rMin + $guess * ($rMax - $rMin),12); - } - return self::$_errorCodes['value']; - } // function BETAINV() - - - // - // Private implementation of the incomplete Gamma function - // - private static function _incompleteGamma($a,$x) { - static $max = 32; - $summer = 0; - for ($n=0; $n<=$max; ++$n) { - $divisor = $a; - for ($i=1; $i<=$n; ++$i) { - $divisor *= ($a + $i); - } - $summer += (pow($x,$n) / $divisor); - } - return pow($x,$a) * exp(0-$x) * $summer; - } // function _incompleteGamma() - - - // - // Private implementation of the Gamma function - // - private static function _gamma($data) { - if ($data == 0.0) return 0; - - static $p0 = 1.000000000190015; - static $p = array ( 1 => 76.18009172947146, - 2 => -86.50532032941677, - 3 => 24.01409824083091, - 4 => -1.231739572450155, - 5 => 1.208650973866179e-3, - 6 => -5.395239384953e-6 - ); - - $y = $x = $data; - $tmp = $x + 5.5; - $tmp -= ($x + 0.5) * log($tmp); - - $summer = $p0; - for ($j=1;$j<=6;++$j) { - $summer += ($p[$j] / ++$y); - } - return exp(0 - $tmp + log(SQRT2PI * $summer / $x)); - } // function _gamma() - - - /** - * GAMMADIST - * - * Returns the gamma distribution. - * - * @param float $value Value at which you want to evaluate the distribution - * @param float $a Parameter to the distribution - * @param float $b Parameter to the distribution - * @param boolean $cumulative - * @return float - * - */ - public static function GAMMADIST($value,$a,$b,$cumulative) { - $value = self::flattenSingleValue($value); - $a = self::flattenSingleValue($a); - $b = self::flattenSingleValue($b); - - if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) { - if (($value < 0) || ($a <= 0) || ($b <= 0)) { - return self::$_errorCodes['num']; - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return self::_incompleteGamma($a,$value / $b) / self::_gamma($a); - } else { - return (1 / (pow($b,$a) * self::_gamma($a))) * pow($value,$a-1) * exp(0-($value / $b)); - } - } - } - return self::$_errorCodes['value']; - } // function GAMMADIST() - - - /** - * GAMMAINV - * - * Returns the inverse of the beta distribution. - * - * @param float $probability Probability at which you want to evaluate the distribution - * @param float $alpha Parameter to the distribution - * @param float $beta Parameter to the distribution - * @return float - * - */ - public static function GAMMAINV($probability,$alpha,$beta) { - $probability = self::flattenSingleValue($probability); - $alpha = self::flattenSingleValue($alpha); - $beta = self::flattenSingleValue($beta); - - if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) { - if (($alpha <= 0) || ($beta <= 0) || ($probability < 0) || ($probability > 1)) { - return self::$_errorCodes['num']; - } - - $xLo = 0; - $xHi = $alpha * $beta * 5; - - $x = $xNew = 1; - $error = $pdf = 0; - $dx = 1024; - $i = 0; - - while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { - // Apply Newton-Raphson step - $error = self::GAMMADIST($x, $alpha, $beta, True) - $probability; - if ($error < 0.0) { - $xLo = $x; - } else { - $xHi = $x; - } - $pdf = self::GAMMADIST($x, $alpha, $beta, False); - // Avoid division by zero - if ($pdf != 0.0) { - $dx = $error / $pdf; - $xNew = $x - $dx; - } - // If the NR fails to converge (which for example may be the - // case if the initial guess is too rough) we apply a bisection - // step to determine a more narrow interval around the root. - if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) { - $xNew = ($xLo + $xHi) / 2; - $dx = $xNew - $x; - } - $x = $xNew; - } - if ($i == MAX_ITERATIONS) { - return self::$_errorCodes['na']; - } - return $x; - } - return self::$_errorCodes['value']; - } // function GAMMAINV() - - - /** - * GAMMALN - * - * Returns the natural logarithm of the gamma function. - * - * @param float $value - * @return float - */ - public static function GAMMALN($value) { - $value = self::flattenSingleValue($value); - - if (is_numeric($value)) { - if ($value <= 0) { - return self::$_errorCodes['num']; - } - return log(self::_gamma($value)); - } - return self::$_errorCodes['value']; - } // function GAMMALN() - - - /** - * NORMDIST - * - * Returns the normal distribution for the specified mean and standard deviation. This - * function has a very wide range of applications in statistics, including hypothesis - * testing. - * - * @param float $value - * @param float $mean Mean Value - * @param float $stdDev Standard Deviation - * @param boolean $cumulative - * @return float - * - */ - public static function NORMDIST($value, $mean, $stdDev, $cumulative) { - $value = self::flattenSingleValue($value); - $mean = self::flattenSingleValue($mean); - $stdDev = self::flattenSingleValue($stdDev); - - if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if ($stdDev < 0) { - return self::$_errorCodes['num']; - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return 0.5 * (1 + self::_erfVal(($value - $mean) / ($stdDev * sqrt(2)))); - } else { - return (1 / (SQRT2PI * $stdDev)) * exp(0 - (pow($value - $mean,2) / (2 * ($stdDev * $stdDev)))); - } - } - } - return self::$_errorCodes['value']; - } // function NORMDIST() - - - /** - * NORMSDIST - * - * Returns the standard normal cumulative distribution function. The distribution has - * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a - * table of standard normal curve areas. - * - * @param float $value - * @return float - */ - public static function NORMSDIST($value) { - $value = self::flattenSingleValue($value); - - return self::NORMDIST($value, 0, 1, True); - } // function NORMSDIST() - - - /** - * LOGNORMDIST - * - * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed - * with parameters mean and standard_dev. - * - * @param float $value - * @return float - */ - public static function LOGNORMDIST($value, $mean, $stdDev) { - $value = self::flattenSingleValue($value); - $mean = self::flattenSingleValue($mean); - $stdDev = self::flattenSingleValue($stdDev); - - if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if (($value <= 0) || ($stdDev <= 0)) { - return self::$_errorCodes['num']; - } - return self::NORMSDIST((log($value) - $mean) / $stdDev); - } - return self::$_errorCodes['value']; - } // function LOGNORMDIST() - - - /*************************************************************************** - * inverse_ncdf.php - * ------------------- - * begin : Friday, January 16, 2004 - * copyright : (C) 2004 Michael Nickerson - * email : nickersonm@yahoo.com - * - ***************************************************************************/ - private static function _inverse_ncdf($p) { - // Inverse ncdf approximation by Peter J. Acklam, implementation adapted to - // PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as - // a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html - // I have not checked the accuracy of this implementation. Be aware that PHP - // will truncate the coeficcients to 14 digits. - - // You have permission to use and distribute this function freely for - // whatever purpose you want, but please show common courtesy and give credit - // where credit is due. - - // Input paramater is $p - probability - where 0 < p < 1. - - // Coefficients in rational approximations - static $a = array( 1 => -3.969683028665376e+01, - 2 => 2.209460984245205e+02, - 3 => -2.759285104469687e+02, - 4 => 1.383577518672690e+02, - 5 => -3.066479806614716e+01, - 6 => 2.506628277459239e+00 - ); - - static $b = array( 1 => -5.447609879822406e+01, - 2 => 1.615858368580409e+02, - 3 => -1.556989798598866e+02, - 4 => 6.680131188771972e+01, - 5 => -1.328068155288572e+01 - ); - - static $c = array( 1 => -7.784894002430293e-03, - 2 => -3.223964580411365e-01, - 3 => -2.400758277161838e+00, - 4 => -2.549732539343734e+00, - 5 => 4.374664141464968e+00, - 6 => 2.938163982698783e+00 - ); - - static $d = array( 1 => 7.784695709041462e-03, - 2 => 3.224671290700398e-01, - 3 => 2.445134137142996e+00, - 4 => 3.754408661907416e+00 - ); - - // Define lower and upper region break-points. - $p_low = 0.02425; //Use lower region approx. below this - $p_high = 1 - $p_low; //Use upper region approx. above this - - if (0 < $p && $p < $p_low) { - // Rational approximation for lower region. - $q = sqrt(-2 * log($p)); - return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / - (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); - } elseif ($p_low <= $p && $p <= $p_high) { - // Rational approximation for central region. - $q = $p - 0.5; - $r = $q * $q; - return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q / - ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1); - } elseif ($p_high < $p && $p < 1) { - // Rational approximation for upper region. - $q = sqrt(-2 * log(1 - $p)); - return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / - (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); - } - // If 0 < p < 1, return a null value - return self::$_errorCodes['null']; - } // function _inverse_ncdf() - - - private static function _inverse_ncdf2($prob) { - // Approximation of inverse standard normal CDF developed by - // B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58. - - $a1 = 2.50662823884; - $a2 = -18.61500062529; - $a3 = 41.39119773534; - $a4 = -25.44106049637; - - $b1 = -8.4735109309; - $b2 = 23.08336743743; - $b3 = -21.06224101826; - $b4 = 3.13082909833; - - $c1 = 0.337475482272615; - $c2 = 0.976169019091719; - $c3 = 0.160797971491821; - $c4 = 2.76438810333863E-02; - $c5 = 3.8405729373609E-03; - $c6 = 3.951896511919E-04; - $c7 = 3.21767881768E-05; - $c8 = 2.888167364E-07; - $c9 = 3.960315187E-07; - - $y = $prob - 0.5; - if (abs($y) < 0.42) { - $z = ($y * $y); - $z = $y * ((($a4 * $z + $a3) * $z + $a2) * $z + $a1) / (((($b4 * $z + $b3) * $z + $b2) * $z + $b1) * $z + 1); - } else { - if ($y > 0) { - $z = log(-log(1 - $prob)); - } else { - $z = log(-log($prob)); - } - $z = $c1 + $z * ($c2 + $z * ($c3 + $z * ($c4 + $z * ($c5 + $z * ($c6 + $z * ($c7 + $z * ($c8 + $z * $c9))))))); - if ($y < 0) { - $z = -$z; - } - } - return $z; - } // function _inverse_ncdf2() - - - private static function _inverse_ncdf3($p) { - // ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3. - // Produces the normal deviate Z corresponding to a given lower - // tail area of P; Z is accurate to about 1 part in 10**16. - // - // This is a PHP version of the original FORTRAN code that can - // be found at http://lib.stat.cmu.edu/apstat/ - $split1 = 0.425; - $split2 = 5; - $const1 = 0.180625; - $const2 = 1.6; - - // coefficients for p close to 0.5 - $a0 = 3.3871328727963666080; - $a1 = 1.3314166789178437745E+2; - $a2 = 1.9715909503065514427E+3; - $a3 = 1.3731693765509461125E+4; - $a4 = 4.5921953931549871457E+4; - $a5 = 6.7265770927008700853E+4; - $a6 = 3.3430575583588128105E+4; - $a7 = 2.5090809287301226727E+3; - - $b1 = 4.2313330701600911252E+1; - $b2 = 6.8718700749205790830E+2; - $b3 = 5.3941960214247511077E+3; - $b4 = 2.1213794301586595867E+4; - $b5 = 3.9307895800092710610E+4; - $b6 = 2.8729085735721942674E+4; - $b7 = 5.2264952788528545610E+3; - - // coefficients for p not close to 0, 0.5 or 1. - $c0 = 1.42343711074968357734; - $c1 = 4.63033784615654529590; - $c2 = 5.76949722146069140550; - $c3 = 3.64784832476320460504; - $c4 = 1.27045825245236838258; - $c5 = 2.41780725177450611770E-1; - $c6 = 2.27238449892691845833E-2; - $c7 = 7.74545014278341407640E-4; - - $d1 = 2.05319162663775882187; - $d2 = 1.67638483018380384940; - $d3 = 6.89767334985100004550E-1; - $d4 = 1.48103976427480074590E-1; - $d5 = 1.51986665636164571966E-2; - $d6 = 5.47593808499534494600E-4; - $d7 = 1.05075007164441684324E-9; - - // coefficients for p near 0 or 1. - $e0 = 6.65790464350110377720; - $e1 = 5.46378491116411436990; - $e2 = 1.78482653991729133580; - $e3 = 2.96560571828504891230E-1; - $e4 = 2.65321895265761230930E-2; - $e5 = 1.24266094738807843860E-3; - $e6 = 2.71155556874348757815E-5; - $e7 = 2.01033439929228813265E-7; - - $f1 = 5.99832206555887937690E-1; - $f2 = 1.36929880922735805310E-1; - $f3 = 1.48753612908506148525E-2; - $f4 = 7.86869131145613259100E-4; - $f5 = 1.84631831751005468180E-5; - $f6 = 1.42151175831644588870E-7; - $f7 = 2.04426310338993978564E-15; - - $q = $p - 0.5; - - // computation for p close to 0.5 - if (abs($q) <= split1) { - $R = $const1 - $q * $q; - $z = $q * ((((((($a7 * $R + $a6) * $R + $a5) * $R + $a4) * $R + $a3) * $R + $a2) * $R + $a1) * $R + $a0) / - ((((((($b7 * $R + $b6) * $R + $b5) * $R + $b4) * $R + $b3) * $R + $b2) * $R + $b1) * $R + 1); - } else { - if ($q < 0) { - $R = $p; - } else { - $R = 1 - $p; - } - $R = pow(-log($R),2); - - // computation for p not close to 0, 0.5 or 1. - If ($R <= $split2) { - $R = $R - $const2; - $z = ((((((($c7 * $R + $c6) * $R + $c5) * $R + $c4) * $R + $c3) * $R + $c2) * $R + $c1) * $R + $c0) / - ((((((($d7 * $R + $d6) * $R + $d5) * $R + $d4) * $R + $d3) * $R + $d2) * $R + $d1) * $R + 1); - } else { - // computation for p near 0 or 1. - $R = $R - $split2; - $z = ((((((($e7 * $R + $e6) * $R + $e5) * $R + $e4) * $R + $e3) * $R + $e2) * $R + $e1) * $R + $e0) / - ((((((($f7 * $R + $f6) * $R + $f5) * $R + $f4) * $R + $f3) * $R + $f2) * $R + $f1) * $R + 1); - } - if ($q < 0) { - $z = -$z; - } - } - return $z; - } // function _inverse_ncdf3() - - - /** - * NORMINV - * - * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation. - * - * @param float $value - * @param float $mean Mean Value - * @param float $stdDev Standard Deviation - * @return float - * - */ - public static function NORMINV($probability,$mean,$stdDev) { - $probability = self::flattenSingleValue($probability); - $mean = self::flattenSingleValue($mean); - $stdDev = self::flattenSingleValue($stdDev); - - if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if (($probability < 0) || ($probability > 1)) { - return self::$_errorCodes['num']; - } - if ($stdDev < 0) { - return self::$_errorCodes['num']; - } - return (self::_inverse_ncdf($probability) * $stdDev) + $mean; - } - return self::$_errorCodes['value']; - } // function NORMINV() - - - /** - * NORMSINV - * - * Returns the inverse of the standard normal cumulative distribution - * - * @param float $value - * @return float - */ - public static function NORMSINV($value) { - return self::NORMINV($value, 0, 1); - } // function NORMSINV() - - - /** - * LOGINV - * - * Returns the inverse of the normal cumulative distribution - * - * @param float $value - * @return float - * - * @todo Try implementing P J Acklam's refinement algorithm for greater - * accuracy if I can get my head round the mathematics - * (as described at) http://home.online.no/~pjacklam/notes/invnorm/ - */ - public static function LOGINV($probability, $mean, $stdDev) { - $probability = self::flattenSingleValue($probability); - $mean = self::flattenSingleValue($mean); - $stdDev = self::flattenSingleValue($stdDev); - - if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) { - return self::$_errorCodes['num']; - } - return exp($mean + $stdDev * self::NORMSINV($probability)); - } - return self::$_errorCodes['value']; - } // function LOGINV() - - - /** - * HYPGEOMDIST - * - * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of - * sample successes, given the sample size, population successes, and population size. - * - * @param float $sampleSuccesses Number of successes in the sample - * @param float $sampleNumber Size of the sample - * @param float $populationSuccesses Number of successes in the population - * @param float $populationNumber Population size - * @return float - * - */ - public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber) { - $sampleSuccesses = floor(self::flattenSingleValue($sampleSuccesses)); - $sampleNumber = floor(self::flattenSingleValue($sampleNumber)); - $populationSuccesses = floor(self::flattenSingleValue($populationSuccesses)); - $populationNumber = floor(self::flattenSingleValue($populationNumber)); - - if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) { - if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) { - return self::$_errorCodes['num']; - } - if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) { - return self::$_errorCodes['num']; - } - if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) { - return self::$_errorCodes['num']; - } - return self::COMBIN($populationSuccesses,$sampleSuccesses) * - self::COMBIN($populationNumber - $populationSuccesses,$sampleNumber - $sampleSuccesses) / - self::COMBIN($populationNumber,$sampleNumber); - } - return self::$_errorCodes['value']; - } // function HYPGEOMDIST() - - - /** - * TDIST - * - * Returns the probability of Student's T distribution. - * - * @param float $value Value for the function - * @param float $degrees degrees of freedom - * @param float $tails number of tails (1 or 2) - * @return float - */ - public static function TDIST($value, $degrees, $tails) { - $value = self::flattenSingleValue($value); - $degrees = floor(self::flattenSingleValue($degrees)); - $tails = floor(self::flattenSingleValue($tails)); - - if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) { - if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) { - return self::$_errorCodes['num']; - } - // tdist, which finds the probability that corresponds to a given value - // of t with k degrees of freedom. This algorithm is translated from a - // pascal function on p81 of "Statistical Computing in Pascal" by D - // Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd: - // London). The above Pascal algorithm is itself a translation of the - // fortran algoritm "AS 3" by B E Cooper of the Atlas Computer - // Laboratory as reported in (among other places) "Applied Statistics - // Algorithms", editied by P Griffiths and I D Hill (1985; Ellis - // Horwood Ltd.; W. Sussex, England). - $tterm = $degrees; - $ttheta = atan2($value,sqrt($tterm)); - $tc = cos($ttheta); - $ts = sin($ttheta); - $tsum = 0; - - if (($degrees % 2) == 1) { - $ti = 3; - $tterm = $tc; - } else { - $ti = 2; - $tterm = 1; - } - - $tsum = $tterm; - while ($ti < $degrees) { - $tterm *= $tc * $tc * ($ti - 1) / $ti; - $tsum += $tterm; - $ti += 2; - } - $tsum *= $ts; - if (($degrees % 2) == 1) { $tsum = M_2DIVPI * ($tsum + $ttheta); } - $tValue = 0.5 * (1 + $tsum); - if ($tails == 1) { - return 1 - abs($tValue); - } else { - return 1 - abs((1 - $tValue) - $tValue); - } - } - return self::$_errorCodes['value']; - } // function TDIST() - - - /** - * TINV - * - * Returns the one-tailed probability of the chi-squared distribution. - * - * @param float $probability Probability for the function - * @param float $degrees degrees of freedom - * @return float - */ - public static function TINV($probability, $degrees) { - $probability = self::flattenSingleValue($probability); - $degrees = floor(self::flattenSingleValue($degrees)); - - if ((is_numeric($probability)) && (is_numeric($degrees))) { - $xLo = 100; - $xHi = 0; - - $x = $xNew = 1; - $dx = 1; - $i = 0; - - while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { - // Apply Newton-Raphson step - $result = self::TDIST($x, $degrees, 2); - $error = $result - $probability; - if ($error == 0.0) { - $dx = 0; - } elseif ($error < 0.0) { - $xLo = $x; - } else { - $xHi = $x; - } - // Avoid division by zero - if ($result != 0.0) { - $dx = $error / $result; - $xNew = $x - $dx; - } - // If the NR fails to converge (which for example may be the - // case if the initial guess is too rough) we apply a bisection - // step to determine a more narrow interval around the root. - if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { - $xNew = ($xLo + $xHi) / 2; - $dx = $xNew - $x; - } - $x = $xNew; - } - if ($i == MAX_ITERATIONS) { - return self::$_errorCodes['na']; - } - return round($x,12); - } - return self::$_errorCodes['value']; - } // function TINV() - - - /** - * CONFIDENCE - * - * Returns the confidence interval for a population mean - * - * @param float $alpha - * @param float $stdDev Standard Deviation - * @param float $size - * @return float - * - */ - public static function CONFIDENCE($alpha,$stdDev,$size) { - $alpha = self::flattenSingleValue($alpha); - $stdDev = self::flattenSingleValue($stdDev); - $size = floor(self::flattenSingleValue($size)); - - if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) { - if (($alpha <= 0) || ($alpha >= 1)) { - return self::$_errorCodes['num']; - } - if (($stdDev <= 0) || ($size < 1)) { - return self::$_errorCodes['num']; - } - return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size); - } - return self::$_errorCodes['value']; - } // function CONFIDENCE() - - - /** - * POISSON - * - * Returns the Poisson distribution. A common application of the Poisson distribution - * is predicting the number of events over a specific time, such as the number of - * cars arriving at a toll plaza in 1 minute. - * - * @param float $value - * @param float $mean Mean Value - * @param boolean $cumulative - * @return float - * - */ - public static function POISSON($value, $mean, $cumulative) { - $value = self::flattenSingleValue($value); - $mean = self::flattenSingleValue($mean); - - if ((is_numeric($value)) && (is_numeric($mean))) { - if (($value <= 0) || ($mean <= 0)) { - return self::$_errorCodes['num']; - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - $summer = 0; - for ($i = 0; $i <= floor($value); ++$i) { - $summer += pow($mean,$i) / self::FACT($i); - } - return exp(0-$mean) * $summer; - } else { - return (exp(0-$mean) * pow($mean,$value)) / self::FACT($value); - } - } - } - return self::$_errorCodes['value']; - } // function POISSON() - - - /** - * WEIBULL - * - * Returns the Weibull distribution. Use this distribution in reliability - * analysis, such as calculating a device's mean time to failure. - * - * @param float $value - * @param float $alpha Alpha Parameter - * @param float $beta Beta Parameter - * @param boolean $cumulative - * @return float - * - */ - public static function WEIBULL($value, $alpha, $beta, $cumulative) { - $value = self::flattenSingleValue($value); - $alpha = self::flattenSingleValue($alpha); - $beta = self::flattenSingleValue($beta); - - if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) { - if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) { - return self::$_errorCodes['num']; - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return 1 - exp(0 - pow($value / $beta,$alpha)); - } else { - return ($alpha / pow($beta,$alpha)) * pow($value,$alpha - 1) * exp(0 - pow($value / $beta,$alpha)); - } - } - } - return self::$_errorCodes['value']; - } // function WEIBULL() - - - /** - * ZTEST - * - * Returns the Weibull distribution. Use this distribution in reliability - * analysis, such as calculating a device's mean time to failure. - * - * @param float $value - * @param float $alpha Alpha Parameter - * @param float $beta Beta Parameter - * @param boolean $cumulative - * @return float - * - */ - public static function ZTEST($dataSet, $m0, $sigma=null) { - $dataSet = self::flattenArrayIndexed($dataSet); - $m0 = self::flattenSingleValue($m0); - $sigma = self::flattenSingleValue($sigma); - - if (is_null($sigma)) { - $sigma = self::STDEV($dataSet); - } - $n = count($dataSet); - - return 1 - self::NORMSDIST((self::AVERAGE($dataSet) - $m0)/($sigma/SQRT($n))); - } // function ZTEST() - - - /** - * SKEW - * - * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry - * of a distribution around its mean. Positive skewness indicates a distribution with an - * asymmetric tail extending toward more positive values. Negative skewness indicates a - * distribution with an asymmetric tail extending toward more negative values. - * - * @param array Data Series - * @return float - */ - public static function SKEW() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - $mean = self::AVERAGE($aArgs); - $stdDev = self::STDEV($aArgs); - - $count = $summer = 0; - // Loop through arguments - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - (!self::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $summer += pow((($arg - $mean) / $stdDev),3) ; - ++$count; - } - } - } - - // Return - if ($count > 2) { - return $summer * ($count / (($count-1) * ($count-2))); - } - return self::$_errorCodes['divisionbyzero']; - } // function SKEW() - - - /** - * KURT - * - * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness - * or flatness of a distribution compared with the normal distribution. Positive - * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a - * relatively flat distribution. - * - * @param array Data Series - * @return float - */ - public static function KURT() { - $aArgs = self::flattenArrayIndexed(func_get_args()); - $mean = self::AVERAGE($aArgs); - $stdDev = self::STDEV($aArgs); - - if ($stdDev > 0) { - $count = $summer = 0; - // Loop through arguments - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && - (!self::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $summer += pow((($arg - $mean) / $stdDev),4) ; - ++$count; - } - } - } - - // Return - if ($count > 3) { - return $summer * ($count * ($count+1) / (($count-1) * ($count-2) * ($count-3))) - (3 * pow($count-1,2) / (($count-2) * ($count-3))); - } - } - return self::$_errorCodes['divisionbyzero']; - } // function KURT() - - - /** - * RAND - * - * @param int $min Minimal value - * @param int $max Maximal value - * @return int Random number - */ - public static function RAND($min = 0, $max = 0) { - $min = self::flattenSingleValue($min); - $max = self::flattenSingleValue($max); - - if ($min == 0 && $max == 0) { - return (rand(0,10000000)) / 10000000; - } else { - return rand($min, $max); - } - } // function RAND() - - - /** - * MOD - * - * @param int $a Dividend - * @param int $b Divisor - * @return int Remainder - */ - public static function MOD($a = 1, $b = 1) { - $a = self::flattenSingleValue($a); - $b = self::flattenSingleValue($b); - - if ($b == 0.0) { - return self::$_errorCodes['divisionbyzero']; - } elseif (($a < 0.0) && ($b > 0.0)) { - return $b - fmod(abs($a),$b); - } elseif (($a > 0.0) && ($b < 0.0)) { - return $b + fmod($a,abs($b)); - } - - return fmod($a,$b); - } // function MOD() - - - /** - * CHARACTER - * - * @param string $character Value - * @return int - */ - public static function CHARACTER($character) { - $character = self::flattenSingleValue($character); - - if ((!is_numeric($character)) || ($character < 0)) { - return self::$_errorCodes['value']; - } - - if (function_exists('mb_convert_encoding')) { - return mb_convert_encoding('&#'.intval($character).';', 'UTF-8', 'HTML-ENTITIES'); - } else { - return chr(intval($character)); - } - } - - - private static function _uniord($c) { - if (ord($c{0}) >=0 && ord($c{0}) <= 127) - return ord($c{0}); - if (ord($c{0}) >= 192 && ord($c{0}) <= 223) - return (ord($c{0})-192)*64 + (ord($c{1})-128); - if (ord($c{0}) >= 224 && ord($c{0}) <= 239) - return (ord($c{0})-224)*4096 + (ord($c{1})-128)*64 + (ord($c{2})-128); - if (ord($c{0}) >= 240 && ord($c{0}) <= 247) - return (ord($c{0})-240)*262144 + (ord($c{1})-128)*4096 + (ord($c{2})-128)*64 + (ord($c{3})-128); - if (ord($c{0}) >= 248 && ord($c{0}) <= 251) - return (ord($c{0})-248)*16777216 + (ord($c{1})-128)*262144 + (ord($c{2})-128)*4096 + (ord($c{3})-128)*64 + (ord($c{4})-128); - if (ord($c{0}) >= 252 && ord($c{0}) <= 253) - return (ord($c{0})-252)*1073741824 + (ord($c{1})-128)*16777216 + (ord($c{2})-128)*262144 + (ord($c{3})-128)*4096 + (ord($c{4})-128)*64 + (ord($c{5})-128); - if (ord($c{0}) >= 254 && ord($c{0}) <= 255) //error - return self::$_errorCodes['value']; - return 0; - } // function _uniord() - - /** - * ASCIICODE - * - * @param string $character Value - * @return int - */ - public static function ASCIICODE($characters) { - $characters = self::flattenSingleValue($characters); - if (is_bool($characters)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $characters = (int) $characters; - } else { - if ($characters) { - $characters = 'True'; - } else { - $characters = 'False'; - } - } - } - - $character = $characters; - if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) { - if (mb_strlen($characters, 'UTF-8') > 1) { $character = mb_substr($characters, 0, 1, 'UTF-8'); } - return self::_uniord($character); - } else { - if (strlen($characters) > 0) { $character = substr($characters, 0, 1); } - return ord($character); - } - } // function ASCIICODE() - - - /** - * CONCATENATE - * - * @return string - */ - public static function CONCATENATE() { - // Return value - $returnValue = ''; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - if (is_bool($arg)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $arg = (int) $arg; - } else { - if ($arg) { - $arg = 'TRUE'; - } else { - $arg = 'FALSE'; - } - } - } - $returnValue .= $arg; - } - - // Return - return $returnValue; - } // function CONCATENATE() - - - /** - * STRINGLENGTH - * - * @param string $value Value - * @param int $chars Number of characters - * @return string - */ - public static function STRINGLENGTH($value = '') { - $value = self::flattenSingleValue($value); - - if (is_bool($value)) { - $value = ($value) ? 'TRUE' : 'FALSE'; - } - - if (function_exists('mb_strlen')) { - return mb_strlen($value, 'UTF-8'); - } else { - return strlen($value); - } - } // function STRINGLENGTH() - - - /** - * SEARCHSENSITIVE - * - * @param string $needle The string to look for - * @param string $haystack The string in which to look - * @param int $offset Offset within $haystack - * @return string - */ - public static function SEARCHSENSITIVE($needle,$haystack,$offset=1) { - $needle = self::flattenSingleValue($needle); - $haystack = self::flattenSingleValue($haystack); - $offset = self::flattenSingleValue($offset); - - if (!is_bool($needle)) { - if (is_bool($haystack)) { - $haystack = ($haystack) ? 'TRUE' : 'FALSE'; - } - - if (($offset > 0) && (strlen($haystack) > $offset)) { - if (function_exists('mb_strpos')) { - $pos = mb_strpos($haystack, $needle, --$offset,'UTF-8'); - } else { - $pos = strpos($haystack, $needle, --$offset); - } - if ($pos !== false) { - return ++$pos; - } - } - } - return self::$_errorCodes['value']; - } // function SEARCHSENSITIVE() - - - /** - * SEARCHINSENSITIVE - * - * @param string $needle The string to look for - * @param string $haystack The string in which to look - * @param int $offset Offset within $haystack - * @return string - */ - public static function SEARCHINSENSITIVE($needle,$haystack,$offset=1) { - $needle = self::flattenSingleValue($needle); - $haystack = self::flattenSingleValue($haystack); - $offset = self::flattenSingleValue($offset); - - if (!is_bool($needle)) { - if (is_bool($haystack)) { - $haystack = ($haystack) ? 'TRUE' : 'FALSE'; - } - - if (($offset > 0) && (strlen($haystack) > $offset)) { - if (function_exists('mb_stripos')) { - $pos = mb_stripos($haystack, $needle, --$offset,'UTF-8'); - } else { - $pos = stripos($haystack, $needle, --$offset); - } - if ($pos !== false) { - return ++$pos; - } - } - } - return self::$_errorCodes['value']; - } // function SEARCHINSENSITIVE() - - - /** - * LEFT - * - * @param string $value Value - * @param int $chars Number of characters - * @return string - */ - public static function LEFT($value = '', $chars = 1) { - $value = self::flattenSingleValue($value); - $chars = self::flattenSingleValue($chars); - - if ($chars < 0) { - return self::$_errorCodes['value']; - } - - if (is_bool($value)) { - $value = ($value) ? 'TRUE' : 'FALSE'; - } - - if (function_exists('mb_substr')) { - return mb_substr($value, 0, $chars, 'UTF-8'); - } else { - return substr($value, 0, $chars); - } - } // function LEFT() - - - /** - * RIGHT - * - * @param string $value Value - * @param int $chars Number of characters - * @return string - */ - public static function RIGHT($value = '', $chars = 1) { - $value = self::flattenSingleValue($value); - $chars = self::flattenSingleValue($chars); - - if ($chars < 0) { - return self::$_errorCodes['value']; - } - - if (is_bool($value)) { - $value = ($value) ? 'TRUE' : 'FALSE'; - } - - if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) { - return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8'); - } else { - return substr($value, strlen($value) - $chars); - } - } // function RIGHT() - - - /** - * MID - * - * @param string $value Value - * @param int $start Start character - * @param int $chars Number of characters - * @return string - */ - public static function MID($value = '', $start = 1, $chars = null) { - $value = self::flattenSingleValue($value); - $start = self::flattenSingleValue($start); - $chars = self::flattenSingleValue($chars); - - if (($start < 1) || ($chars < 0)) { - return self::$_errorCodes['value']; - } - - if (is_bool($value)) { - $value = ($value) ? 'TRUE' : 'FALSE'; - } - - if (function_exists('mb_substr')) { - return mb_substr($value, --$start, $chars, 'UTF-8'); - } else { - return substr($value, --$start, $chars); - } - } // function MID() - - - /** - * REPLACE - * - * @param string $value Value - * @param int $start Start character - * @param int $chars Number of characters - * @return string - */ - public static function REPLACE($oldText = '', $start = 1, $chars = null, $newText) { - $oldText = self::flattenSingleValue($oldText); - $start = self::flattenSingleValue($start); - $chars = self::flattenSingleValue($chars); - $newText = self::flattenSingleValue($newText); - - $left = self::LEFT($oldText,$start-1); - $right = self::RIGHT($oldText,self::STRINGLENGTH($oldText)-($start+$chars)+1); - - return $left.$newText.$right; - } // function REPLACE() - - - /** - * SUBSTITUTE - * - * @param string $text Value - * @param string $fromText From Value - * @param string $toText To Value - * @param integer $instance Instance Number - * @return string - */ - public static function SUBSTITUTE($text = '', $fromText = '', $toText = '', $instance = 0) { - $text = self::flattenSingleValue($text); - $fromText = self::flattenSingleValue($fromText); - $toText = self::flattenSingleValue($toText); - $instance = floor(self::flattenSingleValue($instance)); - - if ($instance == 0) { - if(function_exists('mb_str_replace')) { - return mb_str_replace($fromText,$toText,$text); - } else { - return str_replace($fromText,$toText,$text); - } - } else { - $pos = -1; - while($instance > 0) { - if (function_exists('mb_strpos')) { - $pos = mb_strpos($text, $fromText, $pos+1, 'UTF-8'); - } else { - $pos = strpos($text, $fromText, $pos+1); - } - if ($pos === false) { - break; - } - --$instance; - } - if ($pos !== false) { - if (function_exists('mb_strlen')) { - return self::REPLACE($text,++$pos,mb_strlen($fromText, 'UTF-8'),$toText); - } else { - return self::REPLACE($text,++$pos,strlen($fromText),$toText); - } - } - } - - return $left.$newText.$right; - } // function SUBSTITUTE() - - - /** - * RETURNSTRING - * - * @param mixed $value Value to check - * @return boolean - */ - public static function RETURNSTRING($testValue = '') { - $testValue = self::flattenSingleValue($testValue); - - if (is_string($testValue)) { - return $testValue; - } - return Null; - } // function RETURNSTRING() - - - /** - * FIXEDFORMAT - * - * @param mixed $value Value to check - * @return boolean - */ - public static function FIXEDFORMAT($value,$decimals=2,$no_commas=false) { - $value = self::flattenSingleValue($value); - $decimals = self::flattenSingleValue($decimals); - $no_commas = self::flattenSingleValue($no_commas); - - $valueResult = round($value,$decimals); - if ($decimals < 0) { $decimals = 0; } - if (!$no_commas) { - $valueResult = number_format($valueResult,$decimals); - } - - return (string) $valueResult; - } // function FIXEDFORMAT() - - - /** - * TEXTFORMAT - * - * @param mixed $value Value to check - * @return boolean - */ - public static function TEXTFORMAT($value,$format) { - $value = self::flattenSingleValue($value); - $format = self::flattenSingleValue($format); - - if ((is_string($value)) && (!is_numeric($value)) && PHPExcel_Shared_Date::isDateTimeFormatCode($format)) { - $value = self::DATEVALUE($value); - } - - return (string) PHPExcel_Style_NumberFormat::toFormattedString($value,$format); - } // function TEXTFORMAT() - - - /** - * TRIMSPACES - * - * @param mixed $value Value to check - * @return string - */ - public static function TRIMSPACES($stringValue = '') { - $stringValue = self::flattenSingleValue($stringValue); - - if (is_string($stringValue) || is_numeric($stringValue)) { - return trim(preg_replace('/ +/',' ',$stringValue)); - } - return Null; - } // function TRIMSPACES() - - - private static $_invalidChars = Null; - - /** - * TRIMNONPRINTABLE - * - * @param mixed $value Value to check - * @return string - */ - public static function TRIMNONPRINTABLE($stringValue = '') { - $stringValue = self::flattenSingleValue($stringValue); - - if (is_bool($stringValue)) { - $stringValue = ($stringValue) ? 'TRUE' : 'FALSE'; - } - - if (self::$_invalidChars == Null) { - self::$_invalidChars = range(chr(0),chr(31)); - } - - if (is_string($stringValue) || is_numeric($stringValue)) { - return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F")); - } - return Null; - } // function TRIMNONPRINTABLE() - /** * ERROR_TYPE @@ -5623,7 +417,7 @@ class PHPExcel_Calculation_Functions { * @return boolean */ public static function IS_ODD($value = null) { - $value = self::flattenSingleValue($value); + $value = self::flattenSingleValue($value); if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) { return self::$_errorCodes['value']; @@ -5691,5610 +485,10 @@ class PHPExcel_Calculation_Functions { * @return string Version information */ public static function VERSION() { - return 'PHPExcel 1.7.4, 2010-08-26'; + return 'PHPExcel 1.7.6, 2011-02-27'; } // function VERSION() - /** - * DATE - * - * @param long $year - * @param long $month - * @param long $day - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag - */ - public static function DATE($year = 0, $month = 1, $day = 1) { - $year = (integer) self::flattenSingleValue($year); - $month = (integer) self::flattenSingleValue($month); - $day = (integer) self::flattenSingleValue($day); - - $baseYear = PHPExcel_Shared_Date::getExcelCalendar(); - // Validate parameters - if ($year < ($baseYear-1900)) { - return self::$_errorCodes['num']; - } - if ((($baseYear-1900) != 0) && ($year < $baseYear) && ($year >= 1900)) { - return self::$_errorCodes['num']; - } - - if (($year < $baseYear) && ($year >= ($baseYear-1900))) { - $year += 1900; - } - - if ($month < 1) { - // Handle year/month adjustment if month < 1 - --$month; - $year += ceil($month / 12) - 1; - $month = 13 - abs($month % 12); - } elseif ($month > 12) { - // Handle year/month adjustment if month > 12 - $year += floor($month / 12); - $month = ($month % 12); - } - - // Re-validate the year parameter after adjustments - if (($year < $baseYear) || ($year >= 10000)) { - return self::$_errorCodes['num']; - } - - // Execute function - $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day); - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : return (float) $excelDateValue; - break; - case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue); - break; - case self::RETURNDATE_PHP_OBJECT : return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue); - break; - } - } // function DATE() - - - /** - * TIME - * - * @param long $hour - * @param long $minute - * @param long $second - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag - */ - public static function TIME($hour = 0, $minute = 0, $second = 0) { - $hour = self::flattenSingleValue($hour); - $minute = self::flattenSingleValue($minute); - $second = self::flattenSingleValue($second); - - if ($hour == '') { $hour = 0; } - if ($minute == '') { $minute = 0; } - if ($second == '') { $second = 0; } - - if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) { - return self::$_errorCodes['value']; - } - $hour = (integer) $hour; - $minute = (integer) $minute; - $second = (integer) $second; - - if ($second < 0) { - $minute += floor($second / 60); - $second = 60 - abs($second % 60); - if ($second == 60) { $second = 0; } - } elseif ($second >= 60) { - $minute += floor($second / 60); - $second = $second % 60; - } - if ($minute < 0) { - $hour += floor($minute / 60); - $minute = 60 - abs($minute % 60); - if ($minute == 60) { $minute = 0; } - } elseif ($minute >= 60) { - $hour += floor($minute / 60); - $minute = $minute % 60; - } - - if ($hour > 23) { - $hour = $hour % 24; - } elseif ($hour < 0) { - return self::$_errorCodes['num']; - } - - // Execute function - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : $date = 0; - $calendar = PHPExcel_Shared_Date::getExcelCalendar(); - if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900) { - $date = 1; - } - return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second); - break; - case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(1970, 1, 1, $hour-1, $minute, $second)); // -2147468400; // -2147472000 + 3600 - break; - case self::RETURNDATE_PHP_OBJECT : $dayAdjust = 0; - if ($hour < 0) { - $dayAdjust = floor($hour / 24); - $hour = 24 - abs($hour % 24); - if ($hour == 24) { $hour = 0; } - } elseif ($hour >= 24) { - $dayAdjust = floor($hour / 24); - $hour = $hour % 24; - } - $phpDateObject = new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second); - if ($dayAdjust != 0) { - $phpDateObject->modify($dayAdjust.' days'); - } - return $phpDateObject; - break; - } - } // function TIME() - - - /** - * DATEVALUE - * - * @param string $dateValue - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag - */ - public static function DATEVALUE($dateValue = 1) { - $dateValue = trim(self::flattenSingleValue($dateValue),'"'); - // Strip any ordinals because they're allowed in Excel (English only) - $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui','$1$3',$dateValue); - // Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany) - $dateValue = str_replace(array('/','.','-',' '),array(' ',' ',' ',' '),$dateValue); - - $yearFound = false; - $t1 = explode(' ',$dateValue); - foreach($t1 as &$t) { - if ((is_numeric($t)) && ($t > 31)) { - if ($yearFound) { - return self::$_errorCodes['value']; - } else { - if ($t < 100) { $t += 1900; } - $yearFound = true; - } - } - } - if ((count($t1) == 1) && (strpos($t,':') != false)) { - // We've been fed a time value without any date - return 0.0; - } elseif (count($t1) == 2) { - // We only have two parts of the date: either day/month or month/year - if ($yearFound) { - array_unshift($t1,1); - } else { - array_push($t1,date('Y')); - } - } - unset($t); - $dateValue = implode(' ',$t1); - - $PHPDateArray = date_parse($dateValue); - if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) { - $testVal1 = strtok($dateValue,'- '); - if ($testVal1 !== False) { - $testVal2 = strtok('- '); - if ($testVal2 !== False) { - $testVal3 = strtok('- '); - if ($testVal3 === False) { - $testVal3 = strftime('%Y'); - } - } else { - return self::$_errorCodes['value']; - } - } else { - return self::$_errorCodes['value']; - } - $PHPDateArray = date_parse($testVal1.'-'.$testVal2.'-'.$testVal3); - if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) { - $PHPDateArray = date_parse($testVal2.'-'.$testVal1.'-'.$testVal3); - if (($PHPDateArray === False) || ($PHPDateArray['error_count'] > 0)) { - return self::$_errorCodes['value']; - } - } - } - - if (($PHPDateArray !== False) && ($PHPDateArray['error_count'] == 0)) { - // Execute function - if ($PHPDateArray['year'] == '') { $PHPDateArray['year'] = strftime('%Y'); } - if ($PHPDateArray['month'] == '') { $PHPDateArray['month'] = strftime('%m'); } - if ($PHPDateArray['day'] == '') { $PHPDateArray['day'] = strftime('%d'); } - $excelDateValue = floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second'])); - - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : return (float) $excelDateValue; - break; - case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue); - break; - case self::RETURNDATE_PHP_OBJECT : return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00'); - break; - } - } - return self::$_errorCodes['value']; - } // function DATEVALUE() - - - /** - * _getDateValue - * - * @param string $dateValue - * @return mixed Excel date/time serial value, or string if error - */ - private static function _getDateValue($dateValue) { - if (!is_numeric($dateValue)) { - if ((is_string($dateValue)) && (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC)) { - return self::$_errorCodes['value']; - } - if ((is_object($dateValue)) && ($dateValue instanceof PHPExcel_Shared_Date::$dateTimeObjectType)) { - $dateValue = PHPExcel_Shared_Date::PHPToExcel($dateValue); - } else { - $saveReturnDateType = self::getReturnDateType(); - self::setReturnDateType(self::RETURNDATE_EXCEL); - $dateValue = self::DATEVALUE($dateValue); - self::setReturnDateType($saveReturnDateType); - } - } - return $dateValue; - } // function _getDateValue() - - - /** - * TIMEVALUE - * - * @param string $timeValue - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag - */ - public static function TIMEVALUE($timeValue) { - $timeValue = trim(self::flattenSingleValue($timeValue),'"'); - $timeValue = str_replace(array('/','.'),array('-','-'),$timeValue); - - $PHPDateArray = date_parse($timeValue); - if (($PHPDateArray !== False) && ($PHPDateArray['error_count'] == 0)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']); - } else { - $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel(1900,1,1,$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']) - 1; - } - - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : return (float) $excelDateValue; - break; - case self::RETURNDATE_PHP_NUMERIC : return (integer) $phpDateValue = PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+25569) - 3600;; - break; - case self::RETURNDATE_PHP_OBJECT : return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']); - break; - } - } - return self::$_errorCodes['value']; - } // function TIMEVALUE() - - - /** - * _getTimeValue - * - * @param string $timeValue - * @return mixed Excel date/time serial value, or string if error - */ - private static function _getTimeValue($timeValue) { - $saveReturnDateType = self::getReturnDateType(); - self::setReturnDateType(self::RETURNDATE_EXCEL); - $timeValue = self::TIMEVALUE($timeValue); - self::setReturnDateType($saveReturnDateType); - return $timeValue; - } // function _getTimeValue() - - - /** - * DATETIMENOW - * - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag - */ - public static function DATETIMENOW() { - $saveTimeZone = date_default_timezone_get(); - date_default_timezone_set('UTC'); - $retValue = False; - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time()); - break; - case self::RETURNDATE_PHP_NUMERIC : $retValue = (integer) time(); - break; - case self::RETURNDATE_PHP_OBJECT : $retValue = new DateTime(); - break; - } - date_default_timezone_set($saveTimeZone); - - return $retValue; - } // function DATETIMENOW() - - - /** - * DATENOW - * - * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag - */ - public static function DATENOW() { - $saveTimeZone = date_default_timezone_get(); - date_default_timezone_set('UTC'); - $retValue = False; - $excelDateTime = floor(PHPExcel_Shared_Date::PHPToExcel(time())); - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : $retValue = (float) $excelDateTime; - break; - case self::RETURNDATE_PHP_NUMERIC : $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime) - 3600; - break; - case self::RETURNDATE_PHP_OBJECT : $retValue = PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime); - break; - } - date_default_timezone_set($saveTimeZone); - - return $retValue; - } // function DATENOW() - - - private static function _isLeapYear($year) { - return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0)); - } // function _isLeapYear() - - - private static function _dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS) { - if ($startDay == 31) { - --$startDay; - } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::_isLeapYear($startYear))))) { - $startDay = 30; - } - if ($endDay == 31) { - if ($methodUS && $startDay != 30) { - $endDay = 1; - if ($endMonth == 12) { - ++$endYear; - $endMonth = 1; - } else { - ++$endMonth; - } - } else { - $endDay = 30; - } - } - - return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360; - } // function _dateDiff360() - - - /** - * DAYS360 - * - * @param long $startDate Excel date serial value or a standard date string - * @param long $endDate Excel date serial value or a standard date string - * @param boolean $method US or European Method - * @return long PHP date/time serial - */ - public static function DAYS360($startDate = 0, $endDate = 0, $method = false) { - $startDate = self::flattenSingleValue($startDate); - $endDate = self::flattenSingleValue($endDate); - - if (is_string($startDate = self::_getDateValue($startDate))) { - return self::$_errorCodes['value']; - } - if (is_string($endDate = self::_getDateValue($endDate))) { - return self::$_errorCodes['value']; - } - - // Execute function - $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate); - $startDay = $PHPStartDateObject->format('j'); - $startMonth = $PHPStartDateObject->format('n'); - $startYear = $PHPStartDateObject->format('Y'); - - $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate); - $endDay = $PHPEndDateObject->format('j'); - $endMonth = $PHPEndDateObject->format('n'); - $endYear = $PHPEndDateObject->format('Y'); - - return self::_dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method); - } // function DAYS360() - - - /** - * DATEDIF - * - * @param long $startDate Excel date serial value or a standard date string - * @param long $endDate Excel date serial value or a standard date string - * @param string $unit - * @return long Interval between the dates - */ - public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D') { - $startDate = self::flattenSingleValue($startDate); - $endDate = self::flattenSingleValue($endDate); - $unit = strtoupper(self::flattenSingleValue($unit)); - - if (is_string($startDate = self::_getDateValue($startDate))) { - return self::$_errorCodes['value']; - } - if (is_string($endDate = self::_getDateValue($endDate))) { - return self::$_errorCodes['value']; - } - - // Validate parameters - if ($startDate >= $endDate) { - return self::$_errorCodes['num']; - } - - // Execute function - $difference = $endDate - $startDate; - - $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate); - $startDays = $PHPStartDateObject->format('j'); - $startMonths = $PHPStartDateObject->format('n'); - $startYears = $PHPStartDateObject->format('Y'); - - $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate); - $endDays = $PHPEndDateObject->format('j'); - $endMonths = $PHPEndDateObject->format('n'); - $endYears = $PHPEndDateObject->format('Y'); - - $retVal = self::$_errorCodes['num']; - switch ($unit) { - case 'D': - $retVal = intval($difference); - break; - case 'M': - $retVal = intval($endMonths - $startMonths) + (intval($endYears - $startYears) * 12); - // We're only interested in full months - if ($endDays < $startDays) { - --$retVal; - } - break; - case 'Y': - $retVal = intval($endYears - $startYears); - // We're only interested in full months - if ($endMonths < $startMonths) { - --$retVal; - } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) { - --$retVal; - } - break; - case 'MD': - if ($endDays < $startDays) { - $retVal = $endDays; - $PHPEndDateObject->modify('-'.$endDays.' days'); - $adjustDays = $PHPEndDateObject->format('j'); - if ($adjustDays > $startDays) { - $retVal += ($adjustDays - $startDays); - } - } else { - $retVal = $endDays - $startDays; - } - break; - case 'YM': - $retVal = intval($endMonths - $startMonths); - if ($retVal < 0) $retVal = 12 + $retVal; - // We're only interested in full months - if ($endDays < $startDays) { - --$retVal; - } - break; - case 'YD': - $retVal = intval($difference); - if ($endYears > $startYears) { - while ($endYears > $startYears) { - $PHPEndDateObject->modify('-1 year'); - $endYears = $PHPEndDateObject->format('Y'); - } - $retVal = $PHPEndDateObject->format('z') - $PHPStartDateObject->format('z'); - if ($retVal < 0) { $retVal += 365; } - } - break; - } - return $retVal; - } // function DATEDIF() - - - /** - * YEARFRAC - * - * Calculates the fraction of the year represented by the number of whole days between two dates (the start_date and the - * end_date). Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or obligations - * to assign to a specific term. - * - * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string - * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string - * @param integer $method Method used for the calculation - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float fraction of the year - */ - public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0) { - $startDate = self::flattenSingleValue($startDate); - $endDate = self::flattenSingleValue($endDate); - $method = self::flattenSingleValue($method); - - if (is_string($startDate = self::_getDateValue($startDate))) { - return self::$_errorCodes['value']; - } - if (is_string($endDate = self::_getDateValue($endDate))) { - return self::$_errorCodes['value']; - } - - if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) { - switch($method) { - case 0 : - return self::DAYS360($startDate,$endDate) / 360; - break; - case 1 : - $days = self::DATEDIF($startDate,$endDate); - $startYear = self::YEAR($startDate); - $endYear = self::YEAR($endDate); - $years = $endYear - $startYear + 1; - $leapDays = 0; - if ($years == 1) { - if (self::_isLeapYear($endYear)) { - $startMonth = self::MONTHOFYEAR($startDate); - $endMonth = self::MONTHOFYEAR($endDate); - $endDay = self::DAYOFMONTH($endDate); - if (($startMonth < 3) || - (($endMonth * 100 + $endDay) >= (2 * 100 + 29))) { - $leapDays += 1; - } - } - } else { - for($year = $startYear; $year <= $endYear; ++$year) { - if ($year == $startYear) { - $startMonth = self::MONTHOFYEAR($startDate); - $startDay = self::DAYOFMONTH($startDate); - if ($startMonth < 3) { - $leapDays += (self::_isLeapYear($year)) ? 1 : 0; - } - } elseif($year == $endYear) { - $endMonth = self::MONTHOFYEAR($endDate); - $endDay = self::DAYOFMONTH($endDate); - if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) { - $leapDays += (self::_isLeapYear($year)) ? 1 : 0; - } - } else { - $leapDays += (self::_isLeapYear($year)) ? 1 : 0; - } - } - if ($years == 2) { - if (($leapDays == 0) && (self::_isLeapYear($startYear)) && ($days > 365)) { - $leapDays = 1; - } elseif ($days < 366) { - $years = 1; - } - } - $leapDays /= $years; - } - return $days / (365 + $leapDays); - break; - case 2 : - return self::DATEDIF($startDate,$endDate) / 360; - break; - case 3 : - return self::DATEDIF($startDate,$endDate) / 365; - break; - case 4 : - return self::DAYS360($startDate,$endDate,True) / 360; - break; - } - } - return self::$_errorCodes['value']; - } // function YEARFRAC() - - - /** - * NETWORKDAYS - * - * @param mixed Start date - * @param mixed End date - * @param array of mixed Optional Date Series - * @return long Interval between the dates - */ - public static function NETWORKDAYS($startDate,$endDate) { - // Retrieve the mandatory start and end date that are referenced in the function definition - $startDate = self::flattenSingleValue($startDate); - $endDate = self::flattenSingleValue($endDate); - // Flush the mandatory start and end date that are referenced in the function definition, and get the optional days - $dateArgs = self::flattenArray(func_get_args()); - array_shift($dateArgs); - array_shift($dateArgs); - - // Validate the start and end dates - if (is_string($startDate = $sDate = self::_getDateValue($startDate))) { - return self::$_errorCodes['value']; - } - $startDate = (float) floor($startDate); - if (is_string($endDate = $eDate = self::_getDateValue($endDate))) { - return self::$_errorCodes['value']; - } - $endDate = (float) floor($endDate); - - if ($sDate > $eDate) { - $startDate = $eDate; - $endDate = $sDate; - } - - // Execute function - $startDoW = 6 - self::DAYOFWEEK($startDate,2); - if ($startDoW < 0) { $startDoW = 0; } - $endDoW = self::DAYOFWEEK($endDate,2); - if ($endDoW >= 6) { $endDoW = 0; } - - $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5; - $partWeekDays = $endDoW + $startDoW; - if ($partWeekDays > 5) { - $partWeekDays -= 5; - } - - // Test any extra holiday parameters - $holidayCountedArray = array(); - foreach ($dateArgs as $holidayDate) { - if (is_string($holidayDate = self::_getDateValue($holidayDate))) { - return self::$_errorCodes['value']; - } - if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { - if ((self::DAYOFWEEK($holidayDate,2) < 6) && (!in_array($holidayDate,$holidayCountedArray))) { - --$partWeekDays; - $holidayCountedArray[] = $holidayDate; - } - } - } - - if ($sDate > $eDate) { - return 0 - ($wholeWeekDays + $partWeekDays); - } - return $wholeWeekDays + $partWeekDays; - } // function NETWORKDAYS() - - - /** - * WORKDAY - * - * @param mixed Start date - * @param mixed number of days for adjustment - * @param array of mixed Optional Date Series - * @return long Interval between the dates - */ - public static function WORKDAY($startDate,$endDays) { - // Retrieve the mandatory start date and days that are referenced in the function definition - $startDate = self::flattenSingleValue($startDate); - $endDays = (int) self::flattenSingleValue($endDays); - // Flush the mandatory start date and days that are referenced in the function definition, and get the optional days - $dateArgs = self::flattenArray(func_get_args()); - array_shift($dateArgs); - array_shift($dateArgs); - - if ((is_string($startDate = self::_getDateValue($startDate))) || (!is_numeric($endDays))) { - return self::$_errorCodes['value']; - } - $startDate = (float) floor($startDate); - // If endDays is 0, we always return startDate - if ($endDays == 0) { return $startDate; } - - $decrementing = ($endDays < 0) ? True : False; - - // Adjust the start date if it falls over a weekend - - $startDoW = self::DAYOFWEEK($startDate,3); - if (self::DAYOFWEEK($startDate,3) >= 5) { - $startDate += ($decrementing) ? -$startDoW + 4: 7 - $startDoW; - ($decrementing) ? $endDays++ : $endDays--; - } - - // Add endDays - $endDate = (float) $startDate + (intval($endDays / 5) * 7) + ($endDays % 5); - - // Adjust the calculated end date if it falls over a weekend - $endDoW = self::DAYOFWEEK($endDate,3); - if ($endDoW >= 5) { - $endDate += ($decrementing) ? -$endDoW + 4: 7 - $endDoW; - } - - // Test any extra holiday parameters - if (count($dateArgs) > 0) { - $holidayCountedArray = $holidayDates = array(); - foreach ($dateArgs as $holidayDate) { - if ((!is_null($holidayDate)) && (trim($holidayDate) > '')) { - if (is_string($holidayDate = self::_getDateValue($holidayDate))) { - return self::$_errorCodes['value']; - } - if (self::DAYOFWEEK($holidayDate,3) < 5) { - $holidayDates[] = $holidayDate; - } - } - } - if ($decrementing) { - rsort($holidayDates, SORT_NUMERIC); - } else { - sort($holidayDates, SORT_NUMERIC); - } - foreach ($holidayDates as $holidayDate) { - if ($decrementing) { - if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) { - if (!in_array($holidayDate,$holidayCountedArray)) { - --$endDate; - $holidayCountedArray[] = $holidayDate; - } - } - } else { - if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { - if (!in_array($holidayDate,$holidayCountedArray)) { - ++$endDate; - $holidayCountedArray[] = $holidayDate; - } - } - } - // Adjust the calculated end date if it falls over a weekend - $endDoW = self::DAYOFWEEK($endDate,3); - if ($endDoW >= 5) { - $endDate += ($decrementing) ? -$endDoW + 4: 7 - $endDoW; - } - - } - } - - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : return (float) $endDate; - break; - case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate); - break; - case self::RETURNDATE_PHP_OBJECT : return PHPExcel_Shared_Date::ExcelToPHPObject($endDate); - break; - } - } // function WORKDAY() - - - /** - * DAYOFMONTH - * - * @param long $dateValue Excel date serial value or a standard date string - * @return int Day - */ - public static function DAYOFMONTH($dateValue = 1) { - $dateValue = self::flattenSingleValue($dateValue); - - if (is_string($dateValue = self::_getDateValue($dateValue))) { - return self::$_errorCodes['value']; - } elseif ($dateValue == 0.0) { - return 0; - } elseif ($dateValue < 0.0) { - return self::$_errorCodes['num']; - } - - // Execute function - $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); - - return (int) $PHPDateObject->format('j'); - } // function DAYOFMONTH() - - - /** - * DAYOFWEEK - * - * @param long $dateValue Excel date serial value or a standard date string - * @return int Day - */ - public static function DAYOFWEEK($dateValue = 1, $style = 1) { - $dateValue = self::flattenSingleValue($dateValue); - $style = floor(self::flattenSingleValue($style)); - - if (is_string($dateValue = self::_getDateValue($dateValue))) { - return self::$_errorCodes['value']; - } elseif ($dateValue < 0.0) { - return self::$_errorCodes['num']; - } - - // Execute function - $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); - $DoW = $PHPDateObject->format('w'); - - $firstDay = 1; - switch ($style) { - case 1: ++$DoW; - break; - case 2: if ($DoW == 0) { $DoW = 7; } - break; - case 3: if ($DoW == 0) { $DoW = 7; } - $firstDay = 0; - --$DoW; - break; - default: - } - if (self::$compatibilityMode == self::COMPATIBILITY_EXCEL) { - // Test for Excel's 1900 leap year, and introduce the error as required - if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) { - --$DoW; - if ($DoW < $firstDay) { - $DoW += 7; - } - } - } - - return (int) $DoW; - } // function DAYOFWEEK() - - - /** - * WEEKOFYEAR - * - * @param long $dateValue Excel date serial value or a standard date string - * @param boolean $method Week begins on Sunday or Monday - * @return int Week Number - */ - public static function WEEKOFYEAR($dateValue = 1, $method = 1) { - $dateValue = self::flattenSingleValue($dateValue); - $method = floor(self::flattenSingleValue($method)); - - if (!is_numeric($method)) { - return self::$_errorCodes['value']; - } elseif (($method < 1) || ($method > 2)) { - return self::$_errorCodes['num']; - } - - if (is_string($dateValue = self::_getDateValue($dateValue))) { - return self::$_errorCodes['value']; - } elseif ($dateValue < 0.0) { - return self::$_errorCodes['num']; - } - - // Execute function - $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); - $dayOfYear = $PHPDateObject->format('z'); - $dow = $PHPDateObject->format('w'); - $PHPDateObject->modify('-'.$dayOfYear.' days'); - $dow = $PHPDateObject->format('w'); - $daysInFirstWeek = 7 - (($dow + (2 - $method)) % 7); - $dayOfYear -= $daysInFirstWeek; - $weekOfYear = ceil($dayOfYear / 7) + 1; - - return (int) $weekOfYear; - } // function WEEKOFYEAR() - - - /** - * MONTHOFYEAR - * - * @param long $dateValue Excel date serial value or a standard date string - * @return int Month - */ - public static function MONTHOFYEAR($dateValue = 1) { - $dateValue = self::flattenSingleValue($dateValue); - - if (is_string($dateValue = self::_getDateValue($dateValue))) { - return self::$_errorCodes['value']; - } elseif ($dateValue < 0.0) { - return self::$_errorCodes['num']; - } - - // Execute function - $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); - - return (int) $PHPDateObject->format('n'); - } // function MONTHOFYEAR() - - - /** - * YEAR - * - * @param long $dateValue Excel date serial value or a standard date string - * @return int Year - */ - public static function YEAR($dateValue = 1) { - $dateValue = self::flattenSingleValue($dateValue); - - if (is_string($dateValue = self::_getDateValue($dateValue))) { - return self::$_errorCodes['value']; - } elseif ($dateValue < 0.0) { - return self::$_errorCodes['num']; - } - - // Execute function - $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); - - return (int) $PHPDateObject->format('Y'); - } // function YEAR() - - - /** - * HOUROFDAY - * - * @param mixed $timeValue Excel time serial value or a standard time string - * @return int Hour - */ - public static function HOUROFDAY($timeValue = 0) { - $timeValue = self::flattenSingleValue($timeValue); - - if (!is_numeric($timeValue)) { - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $testVal = strtok($timeValue,'/-: '); - if (strlen($testVal) < strlen($timeValue)) { - return self::$_errorCodes['value']; - } - } - $timeValue = self::_getTimeValue($timeValue); - if (is_string($timeValue)) { - return self::$_errorCodes['value']; - } - } - // Execute function - if ($timeValue >= 1) { - $timeValue = fmod($timeValue,1); - } elseif ($timeValue < 0.0) { - return self::$_errorCodes['num']; - } - $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue); - - return (int) gmdate('G',$timeValue); - } // function HOUROFDAY() - - - /** - * MINUTEOFHOUR - * - * @param long $timeValue Excel time serial value or a standard time string - * @return int Minute - */ - public static function MINUTEOFHOUR($timeValue = 0) { - $timeValue = $timeTester = self::flattenSingleValue($timeValue); - - if (!is_numeric($timeValue)) { - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $testVal = strtok($timeValue,'/-: '); - if (strlen($testVal) < strlen($timeValue)) { - return self::$_errorCodes['value']; - } - } - $timeValue = self::_getTimeValue($timeValue); - if (is_string($timeValue)) { - return self::$_errorCodes['value']; - } - } - // Execute function - if ($timeValue >= 1) { - $timeValue = fmod($timeValue,1); - } elseif ($timeValue < 0.0) { - return self::$_errorCodes['num']; - } - $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue); - - return (int) gmdate('i',$timeValue); - } // function MINUTEOFHOUR() - - - /** - * SECONDOFMINUTE - * - * @param long $timeValue Excel time serial value or a standard time string - * @return int Second - */ - public static function SECONDOFMINUTE($timeValue = 0) { - $timeValue = self::flattenSingleValue($timeValue); - - if (!is_numeric($timeValue)) { - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $testVal = strtok($timeValue,'/-: '); - if (strlen($testVal) < strlen($timeValue)) { - return self::$_errorCodes['value']; - } - } - $timeValue = self::_getTimeValue($timeValue); - if (is_string($timeValue)) { - return self::$_errorCodes['value']; - } - } - // Execute function - if ($timeValue >= 1) { - $timeValue = fmod($timeValue,1); - } elseif ($timeValue < 0.0) { - return self::$_errorCodes['num']; - } - $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue); - - return (int) gmdate('s',$timeValue); - } // function SECONDOFMINUTE() - - - private static function _adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0) { - // Execute function - $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue); - $oMonth = (int) $PHPDateObject->format('m'); - $oYear = (int) $PHPDateObject->format('Y'); - - $adjustmentMonthsString = (string) $adjustmentMonths; - if ($adjustmentMonths > 0) { - $adjustmentMonthsString = '+'.$adjustmentMonths; - } - if ($adjustmentMonths != 0) { - $PHPDateObject->modify($adjustmentMonthsString.' months'); - } - $nMonth = (int) $PHPDateObject->format('m'); - $nYear = (int) $PHPDateObject->format('Y'); - - $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12); - if ($monthDiff != $adjustmentMonths) { - $adjustDays = (int) $PHPDateObject->format('d'); - $adjustDaysString = '-'.$adjustDays.' days'; - $PHPDateObject->modify($adjustDaysString); - } - return $PHPDateObject; - } // function _adjustDateByMonths() - - - /** - * EDATE - * - * Returns the serial number that represents the date that is the indicated number of months before or after a specified date - * (the start_date). Use EDATE to calculate maturity dates or due dates that fall on the same day of the month as the date of issue. - * - * @param long $dateValue Excel date serial value or a standard date string - * @param int $adjustmentMonths Number of months to adjust by - * @return long Excel date serial value - */ - public static function EDATE($dateValue = 1, $adjustmentMonths = 0) { - $dateValue = self::flattenSingleValue($dateValue); - $adjustmentMonths = floor(self::flattenSingleValue($adjustmentMonths)); - - if (!is_numeric($adjustmentMonths)) { - return self::$_errorCodes['value']; - } - - if (is_string($dateValue = self::_getDateValue($dateValue))) { - return self::$_errorCodes['value']; - } - - // Execute function - $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths); - - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject); - break; - case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject)); - break; - case self::RETURNDATE_PHP_OBJECT : return $PHPDateObject; - break; - } - } // function EDATE() - - - /** - * EOMONTH - * - * Returns the serial number for the last day of the month that is the indicated number of months before or after start_date. - * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month. - * - * @param long $dateValue Excel date serial value or a standard date string - * @param int $adjustmentMonths Number of months to adjust by - * @return long Excel date serial value - */ - public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0) { - $dateValue = self::flattenSingleValue($dateValue); - $adjustmentMonths = floor(self::flattenSingleValue($adjustmentMonths)); - - if (!is_numeric($adjustmentMonths)) { - return self::$_errorCodes['value']; - } - - if (is_string($dateValue = self::_getDateValue($dateValue))) { - return self::$_errorCodes['value']; - } - - // Execute function - $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths+1); - $adjustDays = (int) $PHPDateObject->format('d'); - $adjustDaysString = '-'.$adjustDays.' days'; - $PHPDateObject->modify($adjustDaysString); - - switch (self::getReturnDateType()) { - case self::RETURNDATE_EXCEL : return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject); - break; - case self::RETURNDATE_PHP_NUMERIC : return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject)); - break; - case self::RETURNDATE_PHP_OBJECT : return $PHPDateObject; - break; - } - } // function EOMONTH() - - - /** - * TRUNC - * - * Truncates value to the number of fractional digits by number_digits. - * - * @param float $value - * @param int $number_digits - * @return float Truncated value - */ - public static function TRUNC($value = 0, $number_digits = 0) { - $value = self::flattenSingleValue($value); - $number_digits = self::flattenSingleValue($number_digits); - - // Validate parameters - if ($number_digits < 0) { - return self::$_errorCodes['value']; - } - - // Truncate - if ($number_digits > 0) { - $value = $value * pow(10, $number_digits); - } - $value = intval($value); - if ($number_digits > 0) { - $value = $value / pow(10, $number_digits); - } - - // Return - return $value; - } // function TRUNC() - - /** - * POWER - * - * Computes x raised to the power y. - * - * @param float $x - * @param float $y - * @return float - */ - public static function POWER($x = 0, $y = 2) { - $x = self::flattenSingleValue($x); - $y = self::flattenSingleValue($y); - - // Validate parameters - if ($x == 0 && $y <= 0) { - return self::$_errorCodes['divisionbyzero']; - } - - // Return - return pow($x, $y); - } // function POWER() - - - private static function _nbrConversionFormat($xVal,$places) { - if (!is_null($places)) { - if (strlen($xVal) <= $places) { - return substr(str_pad($xVal,$places,'0',STR_PAD_LEFT),-10); - } else { - return self::$_errorCodes['num']; - } - } - - return substr($xVal,-10); - } // function _nbrConversionFormat() - - - /** - * BINTODEC - * - * Return a binary value as Decimal. - * - * @param string $x - * @return string - */ - public static function BINTODEC($x) { - $x = self::flattenSingleValue($x); - - if (is_bool($x)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return self::$_errorCodes['value']; - } - } - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $x = floor($x); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[01]/',$x,$out)) { - return self::$_errorCodes['num']; - } - if (strlen($x) > 10) { - return self::$_errorCodes['num']; - } elseif (strlen($x) == 10) { - // Two's Complement - $x = substr($x,-9); - return '-'.(512-bindec($x)); - } - return bindec($x); - } // function BINTODEC() - - - /** - * BINTOHEX - * - * Return a binary value as Hex. - * - * @param string $x - * @return string - */ - public static function BINTOHEX($x, $places=null) { - $x = floor(self::flattenSingleValue($x)); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return self::$_errorCodes['value']; - } - } - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $x = floor($x); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[01]/',$x,$out)) { - return self::$_errorCodes['num']; - } - if (strlen($x) > 10) { - return self::$_errorCodes['num']; - } elseif (strlen($x) == 10) { - // Two's Complement - return str_repeat('F',8).substr(strtoupper(dechex(bindec(substr($x,-9)))),-2); - } - $hexVal = (string) strtoupper(dechex(bindec($x))); - - return self::_nbrConversionFormat($hexVal,$places); - } // function BINTOHEX() - - - /** - * BINTOOCT - * - * Return a binary value as Octal. - * - * @param string $x - * @return string - */ - public static function BINTOOCT($x, $places=null) { - $x = floor(self::flattenSingleValue($x)); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return self::$_errorCodes['value']; - } - } - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $x = floor($x); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[01]/',$x,$out)) { - return self::$_errorCodes['num']; - } - if (strlen($x) > 10) { - return self::$_errorCodes['num']; - } elseif (strlen($x) == 10) { - // Two's Complement - return str_repeat('7',7).substr(strtoupper(decoct(bindec(substr($x,-9)))),-3); - } - $octVal = (string) decoct(bindec($x)); - - return self::_nbrConversionFormat($octVal,$places); - } // function BINTOOCT() - - - /** - * DECTOBIN - * - * Return an octal value as binary. - * - * @param string $x - * @return string - */ - public static function DECTOBIN($x, $places=null) { - $x = self::flattenSingleValue($x); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return self::$_errorCodes['value']; - } - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) { - return self::$_errorCodes['value']; - } - $x = (string) floor($x); - $r = decbin($x); - if (strlen($r) == 32) { - // Two's Complement - $r = substr($r,-10); - } elseif (strlen($r) > 11) { - return self::$_errorCodes['num']; - } - - return self::_nbrConversionFormat($r,$places); - } // function DECTOBIN() - - - /** - * DECTOOCT - * - * Return an octal value as binary. - * - * @param string $x - * @return string - */ - public static function DECTOOCT($x, $places=null) { - $x = self::flattenSingleValue($x); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return self::$_errorCodes['value']; - } - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) { - return self::$_errorCodes['value']; - } - $x = (string) floor($x); - $r = decoct($x); - if (strlen($r) == 11) { - // Two's Complement - $r = substr($r,-10); - } - - return self::_nbrConversionFormat($r,$places); - } // function DECTOOCT() - - - /** - * DECTOHEX - * - * Return an octal value as binary. - * - * @param string $x - * @return string - */ - public static function DECTOHEX($x, $places=null) { - $x = self::flattenSingleValue($x); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return self::$_errorCodes['value']; - } - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[-0123456789.]/',$x,$out)) { - return self::$_errorCodes['value']; - } - $x = (string) floor($x); - $r = strtoupper(dechex($x)); - if (strlen($r) == 8) { - // Two's Complement - $r = 'FF'.$r; - } - - return self::_nbrConversionFormat($r,$places); - } // function DECTOHEX() - - - /** - * HEXTOBIN - * - * Return a hex value as binary. - * - * @param string $x - * @return string - */ - public static function HEXTOBIN($x, $places=null) { - $x = self::flattenSingleValue($x); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - return self::$_errorCodes['value']; - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) { - return self::$_errorCodes['num']; - } - $binVal = decbin(hexdec($x)); - - return substr(self::_nbrConversionFormat($binVal,$places),-10); - } // function HEXTOBIN() - - - /** - * HEXTOOCT - * - * Return a hex value as octal. - * - * @param string $x - * @return string - */ - public static function HEXTOOCT($x, $places=null) { - $x = self::flattenSingleValue($x); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - return self::$_errorCodes['value']; - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) { - return self::$_errorCodes['num']; - } - $octVal = decoct(hexdec($x)); - - return self::_nbrConversionFormat($octVal,$places); - } // function HEXTOOCT() - - - /** - * HEXTODEC - * - * Return a hex value as octal. - * - * @param string $x - * @return string - */ - public static function HEXTODEC($x) { - $x = self::flattenSingleValue($x); - - if (is_bool($x)) { - return self::$_errorCodes['value']; - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/',strtoupper($x),$out)) { - return self::$_errorCodes['num']; - } - return hexdec($x); - } // function HEXTODEC() - - - /** - * OCTTOBIN - * - * Return an octal value as binary. - * - * @param string $x - * @return string - */ - public static function OCTTOBIN($x, $places=null) { - $x = self::flattenSingleValue($x); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - return self::$_errorCodes['value']; - } - $x = (string) $x; - if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) { - return self::$_errorCodes['num']; - } - $r = decbin(octdec($x)); - - return self::_nbrConversionFormat($r,$places); - } // function OCTTOBIN() - - - /** - * OCTTODEC - * - * Return an octal value as binary. - * - * @param string $x - * @return string - */ - public static function OCTTODEC($x) { - $x = self::flattenSingleValue($x); - - if (is_bool($x)) { - return self::$_errorCodes['value']; - } - $x = (string) $x; - if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) { - return self::$_errorCodes['num']; - } - return octdec($x); - } // function OCTTODEC() - - - /** - * OCTTOHEX - * - * Return an octal value as hex. - * - * @param string $x - * @return string - */ - public static function OCTTOHEX($x, $places=null) { - $x = self::flattenSingleValue($x); - $places = self::flattenSingleValue($places); - - if (is_bool($x)) { - return self::$_errorCodes['value']; - } - $x = (string) $x; - if (preg_match_all('/[01234567]/',$x,$out) != strlen($x)) { - return self::$_errorCodes['num']; - } - $hexVal = strtoupper(dechex(octdec($x))); - - return self::_nbrConversionFormat($hexVal,$places); - } // function OCTTOHEX() - - - public static function _parseComplex($complexNumber) { - $workString = (string) $complexNumber; - - $realNumber = $imaginary = 0; - // Extract the suffix, if there is one - $suffix = substr($workString,-1); - if (!is_numeric($suffix)) { - $workString = substr($workString,0,-1); - } else { - $suffix = ''; - } - - // Split the input into its Real and Imaginary components - $leadingSign = 0; - if (strlen($workString) > 0) { - $leadingSign = (($workString{0} == '+') || ($workString{0} == '-')) ? 1 : 0; - } - $power = ''; - $realNumber = strtok($workString, '+-'); - if (strtoupper(substr($realNumber,-1)) == 'E') { - $power = strtok('+-'); - ++$leadingSign; - } - - $realNumber = substr($workString,0,strlen($realNumber)+strlen($power)+$leadingSign); - - if ($suffix != '') { - $imaginary = substr($workString,strlen($realNumber)); - - if (($imaginary == '') && (($realNumber == '') || ($realNumber == '+') || ($realNumber == '-'))) { - $imaginary = $realNumber.'1'; - $realNumber = '0'; - } else if ($imaginary == '') { - $imaginary = $realNumber; - $realNumber = '0'; - } elseif (($imaginary == '+') || ($imaginary == '-')) { - $imaginary .= '1'; - } - } - - $complexArray = array( 'real' => $realNumber, - 'imaginary' => $imaginary, - 'suffix' => $suffix - ); - - return $complexArray; - } // function _parseComplex() - - - private static function _cleanComplex($complexNumber) { - if ($complexNumber{0} == '+') $complexNumber = substr($complexNumber,1); - if ($complexNumber{0} == '0') $complexNumber = substr($complexNumber,1); - if ($complexNumber{0} == '.') $complexNumber = '0'.$complexNumber; - if ($complexNumber{0} == '+') $complexNumber = substr($complexNumber,1); - return $complexNumber; - } - - - /** - * COMPLEX - * - * returns a complex number of the form x + yi or x + yj. - * - * @param float $realNumber - * @param float $imaginary - * @param string $suffix - * @return string - */ - public static function COMPLEX($realNumber=0.0, $imaginary=0.0, $suffix='i') { - $realNumber = (is_null($realNumber)) ? 0.0 : (float) self::flattenSingleValue($realNumber); - $imaginary = (is_null($imaginary)) ? 0.0 : (float) self::flattenSingleValue($imaginary); - $suffix = (is_null($suffix)) ? 'i' : self::flattenSingleValue($suffix); - - if (((is_numeric($realNumber)) && (is_numeric($imaginary))) && - (($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))) { - if ($suffix == '') $suffix = 'i'; - if ($realNumber == 0.0) { - if ($imaginary == 0.0) { - return (string) '0'; - } elseif ($imaginary == 1.0) { - return (string) $suffix; - } elseif ($imaginary == -1.0) { - return (string) '-'.$suffix; - } - return (string) $imaginary.$suffix; - } elseif ($imaginary == 0.0) { - return (string) $realNumber; - } elseif ($imaginary == 1.0) { - return (string) $realNumber.'+'.$suffix; - } elseif ($imaginary == -1.0) { - return (string) $realNumber.'-'.$suffix; - } - if ($imaginary > 0) { $imaginary = (string) '+'.$imaginary; } - return (string) $realNumber.$imaginary.$suffix; - } - return self::$_errorCodes['value']; - } // function COMPLEX() - - - /** - * IMAGINARY - * - * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return real - */ - public static function IMAGINARY($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - return $parsedComplex['imaginary']; - } // function IMAGINARY() - - - /** - * IMREAL - * - * Returns the real coefficient of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return real - */ - public static function IMREAL($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - return $parsedComplex['real']; - } // function IMREAL() - - - /** - * IMABS - * - * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return real - */ - public static function IMABS($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - return sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])); - } // function IMABS() - - - /** - * IMARGUMENT - * - * Returns the argument theta of a complex number, i.e. the angle in radians from the real axis to the representation of the number in polar coordinates. - * - * @param string $complexNumber - * @return string - */ - public static function IMARGUMENT($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if ($parsedComplex['real'] == 0.0) { - if ($parsedComplex['imaginary'] == 0.0) { - return 0.0; - } elseif($parsedComplex['imaginary'] < 0.0) { - return M_PI / -2; - } else { - return M_PI / 2; - } - } elseif ($parsedComplex['real'] > 0.0) { - return atan($parsedComplex['imaginary'] / $parsedComplex['real']); - } elseif ($parsedComplex['imaginary'] < 0.0) { - return 0 - (M_PI - atan(abs($parsedComplex['imaginary']) / abs($parsedComplex['real']))); - } else { - return M_PI - atan($parsedComplex['imaginary'] / abs($parsedComplex['real'])); - } - } // function IMARGUMENT() - - - /** - * IMCONJUGATE - * - * Returns the complex conjugate of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMCONJUGATE($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if ($parsedComplex['imaginary'] == 0.0) { - return $parsedComplex['real']; - } else { - return self::_cleanComplex(self::COMPLEX($parsedComplex['real'], 0 - $parsedComplex['imaginary'], $parsedComplex['suffix'])); - } - } // function IMCONJUGATE() - - - /** - * IMCOS - * - * Returns the cosine of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMCOS($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if ($parsedComplex['imaginary'] == 0.0) { - return cos($parsedComplex['real']); - } else { - return self::IMCONJUGATE(self::COMPLEX(cos($parsedComplex['real']) * cosh($parsedComplex['imaginary']),sin($parsedComplex['real']) * sinh($parsedComplex['imaginary']),$parsedComplex['suffix'])); - } - } // function IMCOS() - - - /** - * IMSIN - * - * Returns the sine of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMSIN($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if ($parsedComplex['imaginary'] == 0.0) { - return sin($parsedComplex['real']); - } else { - return self::COMPLEX(sin($parsedComplex['real']) * cosh($parsedComplex['imaginary']),cos($parsedComplex['real']) * sinh($parsedComplex['imaginary']),$parsedComplex['suffix']); - } - } // function IMSIN() - - - /** - * IMSQRT - * - * Returns the square root of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMSQRT($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - $theta = self::IMARGUMENT($complexNumber); - $d1 = cos($theta / 2); - $d2 = sin($theta / 2); - $r = sqrt(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']))); - - if ($parsedComplex['suffix'] == '') { - return self::COMPLEX($d1 * $r,$d2 * $r); - } else { - return self::COMPLEX($d1 * $r,$d2 * $r,$parsedComplex['suffix']); - } - } // function IMSQRT() - - - /** - * IMLN - * - * Returns the natural logarithm of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMLN($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { - return self::$_errorCodes['num']; - } - - $logR = log(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']))); - $t = self::IMARGUMENT($complexNumber); - - if ($parsedComplex['suffix'] == '') { - return self::COMPLEX($logR,$t); - } else { - return self::COMPLEX($logR,$t,$parsedComplex['suffix']); - } - } // function IMLN() - - - /** - * IMLOG10 - * - * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMLOG10($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { - return self::$_errorCodes['num']; - } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) { - return log10($parsedComplex['real']); - } - - return self::IMPRODUCT(log10(EULER),self::IMLN($complexNumber)); - } // function IMLOG10() - - - /** - * IMLOG2 - * - * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMLOG2($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { - return self::$_errorCodes['num']; - } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) { - return log($parsedComplex['real'],2); - } - - return self::IMPRODUCT(log(EULER,2),self::IMLN($complexNumber)); - } // function IMLOG2() - - - /** - * IMEXP - * - * Returns the exponential of a complex number in x + yi or x + yj text format. - * - * @param string $complexNumber - * @return string - */ - public static function IMEXP($complexNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) { - return '1'; - } - - $e = exp($parsedComplex['real']); - $eX = $e * cos($parsedComplex['imaginary']); - $eY = $e * sin($parsedComplex['imaginary']); - - if ($parsedComplex['suffix'] == '') { - return self::COMPLEX($eX,$eY); - } else { - return self::COMPLEX($eX,$eY,$parsedComplex['suffix']); - } - } // function IMEXP() - - - /** - * IMPOWER - * - * Returns a complex number in x + yi or x + yj text format raised to a power. - * - * @param string $complexNumber - * @return string - */ - public static function IMPOWER($complexNumber,$realNumber) { - $complexNumber = self::flattenSingleValue($complexNumber); - $realNumber = self::flattenSingleValue($realNumber); - - if (!is_numeric($realNumber)) { - return self::$_errorCodes['value']; - } - - $parsedComplex = self::_parseComplex($complexNumber); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - $r = sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])); - $rPower = pow($r,$realNumber); - $theta = self::IMARGUMENT($complexNumber) * $realNumber; - if ($theta == 0) { - return 1; - } elseif ($parsedComplex['imaginary'] == 0.0) { - return self::COMPLEX($rPower * cos($theta),$rPower * sin($theta),$parsedComplex['suffix']); - } else { - return self::COMPLEX($rPower * cos($theta),$rPower * sin($theta),$parsedComplex['suffix']); - } - } // function IMPOWER() - - - /** - * IMDIV - * - * Returns the quotient of two complex numbers in x + yi or x + yj text format. - * - * @param string $complexDividend - * @param string $complexDivisor - * @return real - */ - public static function IMDIV($complexDividend,$complexDivisor) { - $complexDividend = self::flattenSingleValue($complexDividend); - $complexDivisor = self::flattenSingleValue($complexDivisor); - - $parsedComplexDividend = self::_parseComplex($complexDividend); - if (!is_array($parsedComplexDividend)) { - return $parsedComplexDividend; - } - - $parsedComplexDivisor = self::_parseComplex($complexDivisor); - if (!is_array($parsedComplexDivisor)) { - return $parsedComplexDividend; - } - - if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] != '') && - ($parsedComplexDividend['suffix'] != $parsedComplexDivisor['suffix'])) { - return self::$_errorCodes['num']; - } - if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] == '')) { - $parsedComplexDivisor['suffix'] = $parsedComplexDividend['suffix']; - } - - $d1 = ($parsedComplexDividend['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['imaginary']); - $d2 = ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['real']) - ($parsedComplexDividend['real'] * $parsedComplexDivisor['imaginary']); - $d3 = ($parsedComplexDivisor['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDivisor['imaginary'] * $parsedComplexDivisor['imaginary']); - - $r = $d1/$d3; - $i = $d2/$d3; - - if ($i > 0.0) { - return self::_cleanComplex($r.'+'.$i.$parsedComplexDivisor['suffix']); - } elseif ($i < 0.0) { - return self::_cleanComplex($r.$i.$parsedComplexDivisor['suffix']); - } else { - return $r; - } - } // function IMDIV() - - - /** - * IMSUB - * - * Returns the difference of two complex numbers in x + yi or x + yj text format. - * - * @param string $complexNumber1 - * @param string $complexNumber2 - * @return real - */ - public static function IMSUB($complexNumber1,$complexNumber2) { - $complexNumber1 = self::flattenSingleValue($complexNumber1); - $complexNumber2 = self::flattenSingleValue($complexNumber2); - - $parsedComplex1 = self::_parseComplex($complexNumber1); - if (!is_array($parsedComplex1)) { - return $parsedComplex1; - } - - $parsedComplex2 = self::_parseComplex($complexNumber2); - if (!is_array($parsedComplex2)) { - return $parsedComplex2; - } - - if ((($parsedComplex1['suffix'] != '') && ($parsedComplex2['suffix'] != '')) && - ($parsedComplex1['suffix'] != $parsedComplex2['suffix'])) { - return self::$_errorCodes['num']; - } elseif (($parsedComplex1['suffix'] == '') && ($parsedComplex2['suffix'] != '')) { - $parsedComplex1['suffix'] = $parsedComplex2['suffix']; - } - - $d1 = $parsedComplex1['real'] - $parsedComplex2['real']; - $d2 = $parsedComplex1['imaginary'] - $parsedComplex2['imaginary']; - - return self::COMPLEX($d1,$d2,$parsedComplex1['suffix']); - } // function IMSUB() - - - /** - * IMSUM - * - * Returns the sum of two or more complex numbers in x + yi or x + yj text format. - * - * @param array of mixed Data Series - * @return real - */ - public static function IMSUM() { - // Return value - $returnValue = self::_parseComplex('0'); - $activeSuffix = ''; - - // Loop through the arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - $parsedComplex = self::_parseComplex($arg); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - - if ($activeSuffix == '') { - $activeSuffix = $parsedComplex['suffix']; - } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) { - return self::$_errorCodes['value']; - } - - $returnValue['real'] += $parsedComplex['real']; - $returnValue['imaginary'] += $parsedComplex['imaginary']; - } - - if ($returnValue['imaginary'] == 0.0) { $activeSuffix = ''; } - return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix); - } // function IMSUM() - - - /** - * IMPRODUCT - * - * Returns the product of two or more complex numbers in x + yi or x + yj text format. - * - * @param array of mixed Data Series - * @return real - */ - public static function IMPRODUCT() { - // Return value - $returnValue = self::_parseComplex('1'); - $activeSuffix = ''; - - // Loop through the arguments - $aArgs = self::flattenArray(func_get_args()); - foreach ($aArgs as $arg) { - $parsedComplex = self::_parseComplex($arg); - if (!is_array($parsedComplex)) { - return $parsedComplex; - } - $workValue = $returnValue; - if (($parsedComplex['suffix'] != '') && ($activeSuffix == '')) { - $activeSuffix = $parsedComplex['suffix']; - } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) { - return self::$_errorCodes['num']; - } - $returnValue['real'] = ($workValue['real'] * $parsedComplex['real']) - ($workValue['imaginary'] * $parsedComplex['imaginary']); - $returnValue['imaginary'] = ($workValue['real'] * $parsedComplex['imaginary']) + ($workValue['imaginary'] * $parsedComplex['real']); - } - - if ($returnValue['imaginary'] == 0.0) { $activeSuffix = ''; } - return self::COMPLEX($returnValue['real'],$returnValue['imaginary'],$activeSuffix); - } // function IMPRODUCT() - - - private static $_conversionUnits = array( 'g' => array( 'Group' => 'Mass', 'Unit Name' => 'Gram', 'AllowPrefix' => True ), - 'sg' => array( 'Group' => 'Mass', 'Unit Name' => 'Slug', 'AllowPrefix' => False ), - 'lbm' => array( 'Group' => 'Mass', 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => False ), - 'u' => array( 'Group' => 'Mass', 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => True ), - 'ozm' => array( 'Group' => 'Mass', 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => False ), - 'm' => array( 'Group' => 'Distance', 'Unit Name' => 'Meter', 'AllowPrefix' => True ), - 'mi' => array( 'Group' => 'Distance', 'Unit Name' => 'Statute mile', 'AllowPrefix' => False ), - 'Nmi' => array( 'Group' => 'Distance', 'Unit Name' => 'Nautical mile', 'AllowPrefix' => False ), - 'in' => array( 'Group' => 'Distance', 'Unit Name' => 'Inch', 'AllowPrefix' => False ), - 'ft' => array( 'Group' => 'Distance', 'Unit Name' => 'Foot', 'AllowPrefix' => False ), - 'yd' => array( 'Group' => 'Distance', 'Unit Name' => 'Yard', 'AllowPrefix' => False ), - 'ang' => array( 'Group' => 'Distance', 'Unit Name' => 'Angstrom', 'AllowPrefix' => True ), - 'Pica' => array( 'Group' => 'Distance', 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => False ), - 'yr' => array( 'Group' => 'Time', 'Unit Name' => 'Year', 'AllowPrefix' => False ), - 'day' => array( 'Group' => 'Time', 'Unit Name' => 'Day', 'AllowPrefix' => False ), - 'hr' => array( 'Group' => 'Time', 'Unit Name' => 'Hour', 'AllowPrefix' => False ), - 'mn' => array( 'Group' => 'Time', 'Unit Name' => 'Minute', 'AllowPrefix' => False ), - 'sec' => array( 'Group' => 'Time', 'Unit Name' => 'Second', 'AllowPrefix' => True ), - 'Pa' => array( 'Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => True ), - 'p' => array( 'Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => True ), - 'atm' => array( 'Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => True ), - 'at' => array( 'Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => True ), - 'mmHg' => array( 'Group' => 'Pressure', 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => True ), - 'N' => array( 'Group' => 'Force', 'Unit Name' => 'Newton', 'AllowPrefix' => True ), - 'dyn' => array( 'Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => True ), - 'dy' => array( 'Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => True ), - 'lbf' => array( 'Group' => 'Force', 'Unit Name' => 'Pound force', 'AllowPrefix' => False ), - 'J' => array( 'Group' => 'Energy', 'Unit Name' => 'Joule', 'AllowPrefix' => True ), - 'e' => array( 'Group' => 'Energy', 'Unit Name' => 'Erg', 'AllowPrefix' => True ), - 'c' => array( 'Group' => 'Energy', 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => True ), - 'cal' => array( 'Group' => 'Energy', 'Unit Name' => 'IT calorie', 'AllowPrefix' => True ), - 'eV' => array( 'Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => True ), - 'ev' => array( 'Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => True ), - 'HPh' => array( 'Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => False ), - 'hh' => array( 'Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => False ), - 'Wh' => array( 'Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => True ), - 'wh' => array( 'Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => True ), - 'flb' => array( 'Group' => 'Energy', 'Unit Name' => 'Foot-pound', 'AllowPrefix' => False ), - 'BTU' => array( 'Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => False ), - 'btu' => array( 'Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => False ), - 'HP' => array( 'Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => False ), - 'h' => array( 'Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => False ), - 'W' => array( 'Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => True ), - 'w' => array( 'Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => True ), - 'T' => array( 'Group' => 'Magnetism', 'Unit Name' => 'Tesla', 'AllowPrefix' => True ), - 'ga' => array( 'Group' => 'Magnetism', 'Unit Name' => 'Gauss', 'AllowPrefix' => True ), - 'C' => array( 'Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => False ), - 'cel' => array( 'Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => False ), - 'F' => array( 'Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => False ), - 'fah' => array( 'Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => False ), - 'K' => array( 'Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => False ), - 'kel' => array( 'Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => False ), - 'tsp' => array( 'Group' => 'Liquid', 'Unit Name' => 'Teaspoon', 'AllowPrefix' => False ), - 'tbs' => array( 'Group' => 'Liquid', 'Unit Name' => 'Tablespoon', 'AllowPrefix' => False ), - 'oz' => array( 'Group' => 'Liquid', 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => False ), - 'cup' => array( 'Group' => 'Liquid', 'Unit Name' => 'Cup', 'AllowPrefix' => False ), - 'pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => False ), - 'us_pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => False ), - 'uk_pt' => array( 'Group' => 'Liquid', 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => False ), - 'qt' => array( 'Group' => 'Liquid', 'Unit Name' => 'Quart', 'AllowPrefix' => False ), - 'gal' => array( 'Group' => 'Liquid', 'Unit Name' => 'Gallon', 'AllowPrefix' => False ), - 'l' => array( 'Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => True ), - 'lt' => array( 'Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => True ) - ); - - private static $_conversionMultipliers = array( 'Y' => array( 'multiplier' => 1E24, 'name' => 'yotta' ), - 'Z' => array( 'multiplier' => 1E21, 'name' => 'zetta' ), - 'E' => array( 'multiplier' => 1E18, 'name' => 'exa' ), - 'P' => array( 'multiplier' => 1E15, 'name' => 'peta' ), - 'T' => array( 'multiplier' => 1E12, 'name' => 'tera' ), - 'G' => array( 'multiplier' => 1E9, 'name' => 'giga' ), - 'M' => array( 'multiplier' => 1E6, 'name' => 'mega' ), - 'k' => array( 'multiplier' => 1E3, 'name' => 'kilo' ), - 'h' => array( 'multiplier' => 1E2, 'name' => 'hecto' ), - 'e' => array( 'multiplier' => 1E1, 'name' => 'deka' ), - 'd' => array( 'multiplier' => 1E-1, 'name' => 'deci' ), - 'c' => array( 'multiplier' => 1E-2, 'name' => 'centi' ), - 'm' => array( 'multiplier' => 1E-3, 'name' => 'milli' ), - 'u' => array( 'multiplier' => 1E-6, 'name' => 'micro' ), - 'n' => array( 'multiplier' => 1E-9, 'name' => 'nano' ), - 'p' => array( 'multiplier' => 1E-12, 'name' => 'pico' ), - 'f' => array( 'multiplier' => 1E-15, 'name' => 'femto' ), - 'a' => array( 'multiplier' => 1E-18, 'name' => 'atto' ), - 'z' => array( 'multiplier' => 1E-21, 'name' => 'zepto' ), - 'y' => array( 'multiplier' => 1E-24, 'name' => 'yocto' ) - ); - - private static $_unitConversions = array( 'Mass' => array( 'g' => array( 'g' => 1.0, - 'sg' => 6.85220500053478E-05, - 'lbm' => 2.20462291469134E-03, - 'u' => 6.02217000000000E+23, - 'ozm' => 3.52739718003627E-02 - ), - 'sg' => array( 'g' => 1.45938424189287E+04, - 'sg' => 1.0, - 'lbm' => 3.21739194101647E+01, - 'u' => 8.78866000000000E+27, - 'ozm' => 5.14782785944229E+02 - ), - 'lbm' => array( 'g' => 4.5359230974881148E+02, - 'sg' => 3.10810749306493E-02, - 'lbm' => 1.0, - 'u' => 2.73161000000000E+26, - 'ozm' => 1.60000023429410E+01 - ), - 'u' => array( 'g' => 1.66053100460465E-24, - 'sg' => 1.13782988532950E-28, - 'lbm' => 3.66084470330684E-27, - 'u' => 1.0, - 'ozm' => 5.85735238300524E-26 - ), - 'ozm' => array( 'g' => 2.83495152079732E+01, - 'sg' => 1.94256689870811E-03, - 'lbm' => 6.24999908478882E-02, - 'u' => 1.70725600000000E+25, - 'ozm' => 1.0 - ) - ), - 'Distance' => array( 'm' => array( 'm' => 1.0, - 'mi' => 6.21371192237334E-04, - 'Nmi' => 5.39956803455724E-04, - 'in' => 3.93700787401575E+01, - 'ft' => 3.28083989501312E+00, - 'yd' => 1.09361329797891E+00, - 'ang' => 1.00000000000000E+10, - 'Pica' => 2.83464566929116E+03 - ), - 'mi' => array( 'm' => 1.60934400000000E+03, - 'mi' => 1.0, - 'Nmi' => 8.68976241900648E-01, - 'in' => 6.33600000000000E+04, - 'ft' => 5.28000000000000E+03, - 'yd' => 1.76000000000000E+03, - 'ang' => 1.60934400000000E+13, - 'Pica' => 4.56191999999971E+06 - ), - 'Nmi' => array( 'm' => 1.85200000000000E+03, - 'mi' => 1.15077944802354E+00, - 'Nmi' => 1.0, - 'in' => 7.29133858267717E+04, - 'ft' => 6.07611548556430E+03, - 'yd' => 2.02537182785694E+03, - 'ang' => 1.85200000000000E+13, - 'Pica' => 5.24976377952723E+06 - ), - 'in' => array( 'm' => 2.54000000000000E-02, - 'mi' => 1.57828282828283E-05, - 'Nmi' => 1.37149028077754E-05, - 'in' => 1.0, - 'ft' => 8.33333333333333E-02, - 'yd' => 2.77777777686643E-02, - 'ang' => 2.54000000000000E+08, - 'Pica' => 7.19999999999955E+01 - ), - 'ft' => array( 'm' => 3.04800000000000E-01, - 'mi' => 1.89393939393939E-04, - 'Nmi' => 1.64578833693305E-04, - 'in' => 1.20000000000000E+01, - 'ft' => 1.0, - 'yd' => 3.33333333223972E-01, - 'ang' => 3.04800000000000E+09, - 'Pica' => 8.63999999999946E+02 - ), - 'yd' => array( 'm' => 9.14400000300000E-01, - 'mi' => 5.68181818368230E-04, - 'Nmi' => 4.93736501241901E-04, - 'in' => 3.60000000118110E+01, - 'ft' => 3.00000000000000E+00, - 'yd' => 1.0, - 'ang' => 9.14400000300000E+09, - 'Pica' => 2.59200000085023E+03 - ), - 'ang' => array( 'm' => 1.00000000000000E-10, - 'mi' => 6.21371192237334E-14, - 'Nmi' => 5.39956803455724E-14, - 'in' => 3.93700787401575E-09, - 'ft' => 3.28083989501312E-10, - 'yd' => 1.09361329797891E-10, - 'ang' => 1.0, - 'Pica' => 2.83464566929116E-07 - ), - 'Pica' => array( 'm' => 3.52777777777800E-04, - 'mi' => 2.19205948372629E-07, - 'Nmi' => 1.90484761219114E-07, - 'in' => 1.38888888888898E-02, - 'ft' => 1.15740740740748E-03, - 'yd' => 3.85802469009251E-04, - 'ang' => 3.52777777777800E+06, - 'Pica' => 1.0 - ) - ), - 'Time' => array( 'yr' => array( 'yr' => 1.0, - 'day' => 365.25, - 'hr' => 8766.0, - 'mn' => 525960.0, - 'sec' => 31557600.0 - ), - 'day' => array( 'yr' => 2.73785078713210E-03, - 'day' => 1.0, - 'hr' => 24.0, - 'mn' => 1440.0, - 'sec' => 86400.0 - ), - 'hr' => array( 'yr' => 1.14077116130504E-04, - 'day' => 4.16666666666667E-02, - 'hr' => 1.0, - 'mn' => 60.0, - 'sec' => 3600.0 - ), - 'mn' => array( 'yr' => 1.90128526884174E-06, - 'day' => 6.94444444444444E-04, - 'hr' => 1.66666666666667E-02, - 'mn' => 1.0, - 'sec' => 60.0 - ), - 'sec' => array( 'yr' => 3.16880878140289E-08, - 'day' => 1.15740740740741E-05, - 'hr' => 2.77777777777778E-04, - 'mn' => 1.66666666666667E-02, - 'sec' => 1.0 - ) - ), - 'Pressure' => array( 'Pa' => array( 'Pa' => 1.0, - 'p' => 1.0, - 'atm' => 9.86923299998193E-06, - 'at' => 9.86923299998193E-06, - 'mmHg' => 7.50061707998627E-03 - ), - 'p' => array( 'Pa' => 1.0, - 'p' => 1.0, - 'atm' => 9.86923299998193E-06, - 'at' => 9.86923299998193E-06, - 'mmHg' => 7.50061707998627E-03 - ), - 'atm' => array( 'Pa' => 1.01324996583000E+05, - 'p' => 1.01324996583000E+05, - 'atm' => 1.0, - 'at' => 1.0, - 'mmHg' => 760.0 - ), - 'at' => array( 'Pa' => 1.01324996583000E+05, - 'p' => 1.01324996583000E+05, - 'atm' => 1.0, - 'at' => 1.0, - 'mmHg' => 760.0 - ), - 'mmHg' => array( 'Pa' => 1.33322363925000E+02, - 'p' => 1.33322363925000E+02, - 'atm' => 1.31578947368421E-03, - 'at' => 1.31578947368421E-03, - 'mmHg' => 1.0 - ) - ), - 'Force' => array( 'N' => array( 'N' => 1.0, - 'dyn' => 1.0E+5, - 'dy' => 1.0E+5, - 'lbf' => 2.24808923655339E-01 - ), - 'dyn' => array( 'N' => 1.0E-5, - 'dyn' => 1.0, - 'dy' => 1.0, - 'lbf' => 2.24808923655339E-06 - ), - 'dy' => array( 'N' => 1.0E-5, - 'dyn' => 1.0, - 'dy' => 1.0, - 'lbf' => 2.24808923655339E-06 - ), - 'lbf' => array( 'N' => 4.448222, - 'dyn' => 4.448222E+5, - 'dy' => 4.448222E+5, - 'lbf' => 1.0 - ) - ), - 'Energy' => array( 'J' => array( 'J' => 1.0, - 'e' => 9.99999519343231E+06, - 'c' => 2.39006249473467E-01, - 'cal' => 2.38846190642017E-01, - 'eV' => 6.24145700000000E+18, - 'ev' => 6.24145700000000E+18, - 'HPh' => 3.72506430801000E-07, - 'hh' => 3.72506430801000E-07, - 'Wh' => 2.77777916238711E-04, - 'wh' => 2.77777916238711E-04, - 'flb' => 2.37304222192651E+01, - 'BTU' => 9.47815067349015E-04, - 'btu' => 9.47815067349015E-04 - ), - 'e' => array( 'J' => 1.00000048065700E-07, - 'e' => 1.0, - 'c' => 2.39006364353494E-08, - 'cal' => 2.38846305445111E-08, - 'eV' => 6.24146000000000E+11, - 'ev' => 6.24146000000000E+11, - 'HPh' => 3.72506609848824E-14, - 'hh' => 3.72506609848824E-14, - 'Wh' => 2.77778049754611E-11, - 'wh' => 2.77778049754611E-11, - 'flb' => 2.37304336254586E-06, - 'BTU' => 9.47815522922962E-11, - 'btu' => 9.47815522922962E-11 - ), - 'c' => array( 'J' => 4.18399101363672E+00, - 'e' => 4.18398900257312E+07, - 'c' => 1.0, - 'cal' => 9.99330315287563E-01, - 'eV' => 2.61142000000000E+19, - 'ev' => 2.61142000000000E+19, - 'HPh' => 1.55856355899327E-06, - 'hh' => 1.55856355899327E-06, - 'Wh' => 1.16222030532950E-03, - 'wh' => 1.16222030532950E-03, - 'flb' => 9.92878733152102E+01, - 'BTU' => 3.96564972437776E-03, - 'btu' => 3.96564972437776E-03 - ), - 'cal' => array( 'J' => 4.18679484613929E+00, - 'e' => 4.18679283372801E+07, - 'c' => 1.00067013349059E+00, - 'cal' => 1.0, - 'eV' => 2.61317000000000E+19, - 'ev' => 2.61317000000000E+19, - 'HPh' => 1.55960800463137E-06, - 'hh' => 1.55960800463137E-06, - 'Wh' => 1.16299914807955E-03, - 'wh' => 1.16299914807955E-03, - 'flb' => 9.93544094443283E+01, - 'BTU' => 3.96830723907002E-03, - 'btu' => 3.96830723907002E-03 - ), - 'eV' => array( 'J' => 1.60219000146921E-19, - 'e' => 1.60218923136574E-12, - 'c' => 3.82933423195043E-20, - 'cal' => 3.82676978535648E-20, - 'eV' => 1.0, - 'ev' => 1.0, - 'HPh' => 5.96826078912344E-26, - 'hh' => 5.96826078912344E-26, - 'Wh' => 4.45053000026614E-23, - 'wh' => 4.45053000026614E-23, - 'flb' => 3.80206452103492E-18, - 'BTU' => 1.51857982414846E-22, - 'btu' => 1.51857982414846E-22 - ), - 'ev' => array( 'J' => 1.60219000146921E-19, - 'e' => 1.60218923136574E-12, - 'c' => 3.82933423195043E-20, - 'cal' => 3.82676978535648E-20, - 'eV' => 1.0, - 'ev' => 1.0, - 'HPh' => 5.96826078912344E-26, - 'hh' => 5.96826078912344E-26, - 'Wh' => 4.45053000026614E-23, - 'wh' => 4.45053000026614E-23, - 'flb' => 3.80206452103492E-18, - 'BTU' => 1.51857982414846E-22, - 'btu' => 1.51857982414846E-22 - ), - 'HPh' => array( 'J' => 2.68451741316170E+06, - 'e' => 2.68451612283024E+13, - 'c' => 6.41616438565991E+05, - 'cal' => 6.41186757845835E+05, - 'eV' => 1.67553000000000E+25, - 'ev' => 1.67553000000000E+25, - 'HPh' => 1.0, - 'hh' => 1.0, - 'Wh' => 7.45699653134593E+02, - 'wh' => 7.45699653134593E+02, - 'flb' => 6.37047316692964E+07, - 'BTU' => 2.54442605275546E+03, - 'btu' => 2.54442605275546E+03 - ), - 'hh' => array( 'J' => 2.68451741316170E+06, - 'e' => 2.68451612283024E+13, - 'c' => 6.41616438565991E+05, - 'cal' => 6.41186757845835E+05, - 'eV' => 1.67553000000000E+25, - 'ev' => 1.67553000000000E+25, - 'HPh' => 1.0, - 'hh' => 1.0, - 'Wh' => 7.45699653134593E+02, - 'wh' => 7.45699653134593E+02, - 'flb' => 6.37047316692964E+07, - 'BTU' => 2.54442605275546E+03, - 'btu' => 2.54442605275546E+03 - ), - 'Wh' => array( 'J' => 3.59999820554720E+03, - 'e' => 3.59999647518369E+10, - 'c' => 8.60422069219046E+02, - 'cal' => 8.59845857713046E+02, - 'eV' => 2.24692340000000E+22, - 'ev' => 2.24692340000000E+22, - 'HPh' => 1.34102248243839E-03, - 'hh' => 1.34102248243839E-03, - 'Wh' => 1.0, - 'wh' => 1.0, - 'flb' => 8.54294774062316E+04, - 'BTU' => 3.41213254164705E+00, - 'btu' => 3.41213254164705E+00 - ), - 'wh' => array( 'J' => 3.59999820554720E+03, - 'e' => 3.59999647518369E+10, - 'c' => 8.60422069219046E+02, - 'cal' => 8.59845857713046E+02, - 'eV' => 2.24692340000000E+22, - 'ev' => 2.24692340000000E+22, - 'HPh' => 1.34102248243839E-03, - 'hh' => 1.34102248243839E-03, - 'Wh' => 1.0, - 'wh' => 1.0, - 'flb' => 8.54294774062316E+04, - 'BTU' => 3.41213254164705E+00, - 'btu' => 3.41213254164705E+00 - ), - 'flb' => array( 'J' => 4.21400003236424E-02, - 'e' => 4.21399800687660E+05, - 'c' => 1.00717234301644E-02, - 'cal' => 1.00649785509554E-02, - 'eV' => 2.63015000000000E+17, - 'ev' => 2.63015000000000E+17, - 'HPh' => 1.56974211145130E-08, - 'hh' => 1.56974211145130E-08, - 'Wh' => 1.17055614802000E-05, - 'wh' => 1.17055614802000E-05, - 'flb' => 1.0, - 'BTU' => 3.99409272448406E-05, - 'btu' => 3.99409272448406E-05 - ), - 'BTU' => array( 'J' => 1.05505813786749E+03, - 'e' => 1.05505763074665E+10, - 'c' => 2.52165488508168E+02, - 'cal' => 2.51996617135510E+02, - 'eV' => 6.58510000000000E+21, - 'ev' => 6.58510000000000E+21, - 'HPh' => 3.93015941224568E-04, - 'hh' => 3.93015941224568E-04, - 'Wh' => 2.93071851047526E-01, - 'wh' => 2.93071851047526E-01, - 'flb' => 2.50369750774671E+04, - 'BTU' => 1.0, - 'btu' => 1.0, - ), - 'btu' => array( 'J' => 1.05505813786749E+03, - 'e' => 1.05505763074665E+10, - 'c' => 2.52165488508168E+02, - 'cal' => 2.51996617135510E+02, - 'eV' => 6.58510000000000E+21, - 'ev' => 6.58510000000000E+21, - 'HPh' => 3.93015941224568E-04, - 'hh' => 3.93015941224568E-04, - 'Wh' => 2.93071851047526E-01, - 'wh' => 2.93071851047526E-01, - 'flb' => 2.50369750774671E+04, - 'BTU' => 1.0, - 'btu' => 1.0, - ) - ), - 'Power' => array( 'HP' => array( 'HP' => 1.0, - 'h' => 1.0, - 'W' => 7.45701000000000E+02, - 'w' => 7.45701000000000E+02 - ), - 'h' => array( 'HP' => 1.0, - 'h' => 1.0, - 'W' => 7.45701000000000E+02, - 'w' => 7.45701000000000E+02 - ), - 'W' => array( 'HP' => 1.34102006031908E-03, - 'h' => 1.34102006031908E-03, - 'W' => 1.0, - 'w' => 1.0 - ), - 'w' => array( 'HP' => 1.34102006031908E-03, - 'h' => 1.34102006031908E-03, - 'W' => 1.0, - 'w' => 1.0 - ) - ), - 'Magnetism' => array( 'T' => array( 'T' => 1.0, - 'ga' => 10000.0 - ), - 'ga' => array( 'T' => 0.0001, - 'ga' => 1.0 - ) - ), - 'Liquid' => array( 'tsp' => array( 'tsp' => 1.0, - 'tbs' => 3.33333333333333E-01, - 'oz' => 1.66666666666667E-01, - 'cup' => 2.08333333333333E-02, - 'pt' => 1.04166666666667E-02, - 'us_pt' => 1.04166666666667E-02, - 'uk_pt' => 8.67558516821960E-03, - 'qt' => 5.20833333333333E-03, - 'gal' => 1.30208333333333E-03, - 'l' => 4.92999408400710E-03, - 'lt' => 4.92999408400710E-03 - ), - 'tbs' => array( 'tsp' => 3.00000000000000E+00, - 'tbs' => 1.0, - 'oz' => 5.00000000000000E-01, - 'cup' => 6.25000000000000E-02, - 'pt' => 3.12500000000000E-02, - 'us_pt' => 3.12500000000000E-02, - 'uk_pt' => 2.60267555046588E-02, - 'qt' => 1.56250000000000E-02, - 'gal' => 3.90625000000000E-03, - 'l' => 1.47899822520213E-02, - 'lt' => 1.47899822520213E-02 - ), - 'oz' => array( 'tsp' => 6.00000000000000E+00, - 'tbs' => 2.00000000000000E+00, - 'oz' => 1.0, - 'cup' => 1.25000000000000E-01, - 'pt' => 6.25000000000000E-02, - 'us_pt' => 6.25000000000000E-02, - 'uk_pt' => 5.20535110093176E-02, - 'qt' => 3.12500000000000E-02, - 'gal' => 7.81250000000000E-03, - 'l' => 2.95799645040426E-02, - 'lt' => 2.95799645040426E-02 - ), - 'cup' => array( 'tsp' => 4.80000000000000E+01, - 'tbs' => 1.60000000000000E+01, - 'oz' => 8.00000000000000E+00, - 'cup' => 1.0, - 'pt' => 5.00000000000000E-01, - 'us_pt' => 5.00000000000000E-01, - 'uk_pt' => 4.16428088074541E-01, - 'qt' => 2.50000000000000E-01, - 'gal' => 6.25000000000000E-02, - 'l' => 2.36639716032341E-01, - 'lt' => 2.36639716032341E-01 - ), - 'pt' => array( 'tsp' => 9.60000000000000E+01, - 'tbs' => 3.20000000000000E+01, - 'oz' => 1.60000000000000E+01, - 'cup' => 2.00000000000000E+00, - 'pt' => 1.0, - 'us_pt' => 1.0, - 'uk_pt' => 8.32856176149081E-01, - 'qt' => 5.00000000000000E-01, - 'gal' => 1.25000000000000E-01, - 'l' => 4.73279432064682E-01, - 'lt' => 4.73279432064682E-01 - ), - 'us_pt' => array( 'tsp' => 9.60000000000000E+01, - 'tbs' => 3.20000000000000E+01, - 'oz' => 1.60000000000000E+01, - 'cup' => 2.00000000000000E+00, - 'pt' => 1.0, - 'us_pt' => 1.0, - 'uk_pt' => 8.32856176149081E-01, - 'qt' => 5.00000000000000E-01, - 'gal' => 1.25000000000000E-01, - 'l' => 4.73279432064682E-01, - 'lt' => 4.73279432064682E-01 - ), - 'uk_pt' => array( 'tsp' => 1.15266000000000E+02, - 'tbs' => 3.84220000000000E+01, - 'oz' => 1.92110000000000E+01, - 'cup' => 2.40137500000000E+00, - 'pt' => 1.20068750000000E+00, - 'us_pt' => 1.20068750000000E+00, - 'uk_pt' => 1.0, - 'qt' => 6.00343750000000E-01, - 'gal' => 1.50085937500000E-01, - 'l' => 5.68260698087162E-01, - 'lt' => 5.68260698087162E-01 - ), - 'qt' => array( 'tsp' => 1.92000000000000E+02, - 'tbs' => 6.40000000000000E+01, - 'oz' => 3.20000000000000E+01, - 'cup' => 4.00000000000000E+00, - 'pt' => 2.00000000000000E+00, - 'us_pt' => 2.00000000000000E+00, - 'uk_pt' => 1.66571235229816E+00, - 'qt' => 1.0, - 'gal' => 2.50000000000000E-01, - 'l' => 9.46558864129363E-01, - 'lt' => 9.46558864129363E-01 - ), - 'gal' => array( 'tsp' => 7.68000000000000E+02, - 'tbs' => 2.56000000000000E+02, - 'oz' => 1.28000000000000E+02, - 'cup' => 1.60000000000000E+01, - 'pt' => 8.00000000000000E+00, - 'us_pt' => 8.00000000000000E+00, - 'uk_pt' => 6.66284940919265E+00, - 'qt' => 4.00000000000000E+00, - 'gal' => 1.0, - 'l' => 3.78623545651745E+00, - 'lt' => 3.78623545651745E+00 - ), - 'l' => array( 'tsp' => 2.02840000000000E+02, - 'tbs' => 6.76133333333333E+01, - 'oz' => 3.38066666666667E+01, - 'cup' => 4.22583333333333E+00, - 'pt' => 2.11291666666667E+00, - 'us_pt' => 2.11291666666667E+00, - 'uk_pt' => 1.75975569552166E+00, - 'qt' => 1.05645833333333E+00, - 'gal' => 2.64114583333333E-01, - 'l' => 1.0, - 'lt' => 1.0 - ), - 'lt' => array( 'tsp' => 2.02840000000000E+02, - 'tbs' => 6.76133333333333E+01, - 'oz' => 3.38066666666667E+01, - 'cup' => 4.22583333333333E+00, - 'pt' => 2.11291666666667E+00, - 'us_pt' => 2.11291666666667E+00, - 'uk_pt' => 1.75975569552166E+00, - 'qt' => 1.05645833333333E+00, - 'gal' => 2.64114583333333E-01, - 'l' => 1.0, - 'lt' => 1.0 - ) - ) - ); - - - /** - * getConversionGroups - * - * @return array - */ - public static function getConversionGroups() { - $conversionGroups = array(); - foreach(self::$_conversionUnits as $conversionUnit) { - $conversionGroups[] = $conversionUnit['Group']; - } - return array_merge(array_unique($conversionGroups)); - } // function getConversionGroups() - - - /** - * getConversionGroupUnits - * - * @return array - */ - public static function getConversionGroupUnits($group = NULL) { - $conversionGroups = array(); - foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup) { - if ((is_null($group)) || ($conversionGroup['Group'] == $group)) { - $conversionGroups[$conversionGroup['Group']][] = $conversionUnit; - } - } - return $conversionGroups; - } // function getConversionGroupUnits() - - - /** - * getConversionGroupUnitDetails - * - * @return array - */ - public static function getConversionGroupUnitDetails($group = NULL) { - $conversionGroups = array(); - foreach(self::$_conversionUnits as $conversionUnit => $conversionGroup) { - if ((is_null($group)) || ($conversionGroup['Group'] == $group)) { - $conversionGroups[$conversionGroup['Group']][] = array( 'unit' => $conversionUnit, - 'description' => $conversionGroup['Unit Name'] - ); - } - } - return $conversionGroups; - } // function getConversionGroupUnitDetails() - - - /** - * getConversionGroups - * - * @return array - */ - public static function getConversionMultipliers() { - return self::$_conversionMultipliers; - } // function getConversionGroups() - - - /** - * CONVERTUOM - * - * @param float $value - * @param string $fromUOM - * @param string $toUOM - * @return float - */ - public static function CONVERTUOM($value, $fromUOM, $toUOM) { - $value = self::flattenSingleValue($value); - $fromUOM = self::flattenSingleValue($fromUOM); - $toUOM = self::flattenSingleValue($toUOM); - - if (!is_numeric($value)) { - return self::$_errorCodes['value']; - } - $fromMultiplier = 1; - if (isset(self::$_conversionUnits[$fromUOM])) { - $unitGroup1 = self::$_conversionUnits[$fromUOM]['Group']; - } else { - $fromMultiplier = substr($fromUOM,0,1); - $fromUOM = substr($fromUOM,1); - if (isset(self::$_conversionMultipliers[$fromMultiplier])) { - $fromMultiplier = self::$_conversionMultipliers[$fromMultiplier]['multiplier']; - } else { - return self::$_errorCodes['na']; - } - if ((isset(self::$_conversionUnits[$fromUOM])) && (self::$_conversionUnits[$fromUOM]['AllowPrefix'])) { - $unitGroup1 = self::$_conversionUnits[$fromUOM]['Group']; - } else { - return self::$_errorCodes['na']; - } - } - $value *= $fromMultiplier; - - $toMultiplier = 1; - if (isset(self::$_conversionUnits[$toUOM])) { - $unitGroup2 = self::$_conversionUnits[$toUOM]['Group']; - } else { - $toMultiplier = substr($toUOM,0,1); - $toUOM = substr($toUOM,1); - if (isset(self::$_conversionMultipliers[$toMultiplier])) { - $toMultiplier = self::$_conversionMultipliers[$toMultiplier]['multiplier']; - } else { - return self::$_errorCodes['na']; - } - if ((isset(self::$_conversionUnits[$toUOM])) && (self::$_conversionUnits[$toUOM]['AllowPrefix'])) { - $unitGroup2 = self::$_conversionUnits[$toUOM]['Group']; - } else { - return self::$_errorCodes['na']; - } - } - if ($unitGroup1 != $unitGroup2) { - return self::$_errorCodes['na']; - } - - if ($fromUOM == $toUOM) { - return 1.0; - } elseif ($unitGroup1 == 'Temperature') { - if (($fromUOM == 'F') || ($fromUOM == 'fah')) { - if (($toUOM == 'F') || ($toUOM == 'fah')) { - return 1.0; - } else { - $value = (($value - 32) / 1.8); - if (($toUOM == 'K') || ($toUOM == 'kel')) { - $value += 273.15; - } - return $value; - } - } elseif ((($fromUOM == 'K') || ($fromUOM == 'kel')) && - (($toUOM == 'K') || ($toUOM == 'kel'))) { - return 1.0; - } elseif ((($fromUOM == 'C') || ($fromUOM == 'cel')) && - (($toUOM == 'C') || ($toUOM == 'cel'))) { - return 1.0; - } - if (($toUOM == 'F') || ($toUOM == 'fah')) { - if (($fromUOM == 'K') || ($fromUOM == 'kel')) { - $value -= 273.15; - } - return ($value * 1.8) + 32; - } - if (($toUOM == 'C') || ($toUOM == 'cel')) { - return $value - 273.15; - } - return $value + 273.15; - } - return ($value * self::$_unitConversions[$unitGroup1][$fromUOM][$toUOM]) / $toMultiplier; - } // function CONVERTUOM() - - - /** - * BESSELI - * - * Returns the modified Bessel function, which is equivalent to the Bessel function evaluated for purely imaginary arguments - * - * @param float $x - * @param float $n - * @return int - */ - public static function BESSELI($x, $n) { - $x = (is_null($x)) ? 0.0 : self::flattenSingleValue($x); - $n = (is_null($n)) ? 0.0 : self::flattenSingleValue($n); - - if ((is_numeric($x)) && (is_numeric($n))) { - $n = floor($n); - if ($n < 0) { - return self::$_errorCodes['num']; - } - $f_2_PI = 2 * M_PI; - - if (abs($x) <= 30) { - $fTerm = pow($x / 2, $n) / self::FACT($n); - $nK = 1; - $fResult = $fTerm; - $fSqrX = ($x * $x) / 4; - do { - $fTerm *= $fSqrX; - $fTerm /= ($nK * ($nK + $n)); - $fResult += $fTerm; - } while ((abs($fTerm) > 1e-10) && (++$nK < 100)); - } else { - $fXAbs = abs($x); - $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs); - if (($n && 1) && ($x < 0)) { - $fResult = -$fResult; - } - } - return $fResult; - } - return self::$_errorCodes['value']; - } // function BESSELI() - - - /** - * BESSELJ - * - * Returns the Bessel function - * - * @param float $x - * @param float $n - * @return int - */ - public static function BESSELJ($x, $n) { - $x = (is_null($x)) ? 0.0 : self::flattenSingleValue($x); - $n = (is_null($n)) ? 0.0 : self::flattenSingleValue($n); - - if ((is_numeric($x)) && (is_numeric($n))) { - $n = floor($n); - if ($n < 0) { - return self::$_errorCodes['num']; - } - $f_PI_DIV_2 = M_PI / 2; - $f_PI_DIV_4 = M_PI / 4; - - $fResult = 0; - if (abs($x) <= 30) { - $fTerm = pow($x / 2, $n) / self::FACT($n); - $nK = 1; - $fResult = $fTerm; - $fSqrX = ($x * $x) / -4; - do { - $fTerm *= $fSqrX; - $fTerm /= ($nK * ($nK + $n)); - $fResult += $fTerm; - } while ((abs($fTerm) > 1e-10) && (++$nK < 100)); - } else { - $fXAbs = abs($x); - $fResult = sqrt(M_2DIVPI / $fXAbs) * cos($fXAbs - $n * $f_PI_DIV_2 - $f_PI_DIV_4); - if (($n && 1) && ($x < 0)) { - $fResult = -$fResult; - } - } - return $fResult; - } - return self::$_errorCodes['value']; - } // function BESSELJ() - - - private static function _Besselk0($fNum) { - if ($fNum <= 2) { - $fNum2 = $fNum * 0.5; - $y = ($fNum2 * $fNum2); - $fRet = -log($fNum2) * self::BESSELI($fNum, 0) + - (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y * - (0.10750e-3 + $y * 0.74e-5)))))); - } else { - $y = 2 / $fNum; - $fRet = exp(-$fNum) / sqrt($fNum) * - (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y * - (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3)))))); - } - return $fRet; - } // function _Besselk0() - - - private static function _Besselk1($fNum) { - if ($fNum <= 2) { - $fNum2 = $fNum * 0.5; - $y = ($fNum2 * $fNum2); - $fRet = log($fNum2) * self::BESSELI($fNum, 1) + - (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y * - (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum; - } else { - $y = 2 / $fNum; - $fRet = exp(-$fNum) / sqrt($fNum) * - (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y * - (0.325614e-2 + $y * (-0.68245e-3))))))); - } - return $fRet; - } // function _Besselk1() - - - /** - * BESSELK - * - * Returns the modified Bessel function, which is equivalent to the Bessel functions evaluated for purely imaginary arguments. - * - * @param float $x - * @param float $ord - * @return float - */ - public static function BESSELK($x, $ord) { - $x = (is_null($x)) ? 0.0 : self::flattenSingleValue($x); - $ord = (is_null($ord)) ? 0.0 : self::flattenSingleValue($ord); - - if ((is_numeric($x)) && (is_numeric($ord))) { - if (($ord < 0) || ($x == 0.0)) { - return self::$_errorCodes['num']; - } - - switch(floor($ord)) { - case 0 : return self::_Besselk0($x); - break; - case 1 : return self::_Besselk1($x); - break; - default : $fTox = 2 / $x; - $fBkm = self::_Besselk0($x); - $fBk = self::_Besselk1($x); - for ($n = 1; $n < $ord; ++$n) { - $fBkp = $fBkm + $n * $fTox * $fBk; - $fBkm = $fBk; - $fBk = $fBkp; - } - } - return $fBk; - } - return self::$_errorCodes['value']; - } // function BESSELK() - - - private static function _Bessely0($fNum) { - if ($fNum < 8.0) { - $y = ($fNum * $fNum); - $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733)))); - $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y)))); - $fRet = $f1 / $f2 + M_2DIVPI * self::BESSELJ($fNum, 0) * log($fNum); - } else { - $z = 8.0 / $fNum; - $y = ($z * $z); - $xx = $fNum - 0.785398164; - $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6))); - $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7)))); - $fRet = sqrt(M_2DIVPI / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2); - } - return $fRet; - } // function _Bessely0() - - - private static function _Bessely1($fNum) { - if ($fNum < 8.0) { - $y = ($fNum * $fNum); - $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y * - (-0.4237922726e7 + $y * 0.8511937935e4))))); - $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y * - (0.1020426050e6 + $y * (0.3549632885e3 + $y))))); - $fRet = $f1 / $f2 + M_2DIVPI * ( self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum); - } else { - $z = 8.0 / $fNum; - $y = ($z * $z); - $xx = $fNum - 2.356194491; - $f1 = 1 + $y * (0.183105e-2 + $y * (-0.3516396496e-4 + $y * (0.2457520174e-5 + $y * (-0.240337019e6)))); - $f2 = 0.04687499995 + $y * (-0.2002690873e-3 + $y * (0.8449199096e-5 + $y * (-0.88228987e-6 + $y * 0.105787412e-6))); - $fRet = sqrt(M_2DIVPI / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2); - #i12430# ...but this seems to work much better. -// $fRet = sqrt(M_2DIVPI / $fNum) * sin($fNum - 2.356194491); - } - return $fRet; - } // function _Bessely1() - - - /** - * BESSELY - * - * Returns the Bessel function, which is also called the Weber function or the Neumann function. - * - * @param float $x - * @param float $n - * @return int - */ - public static function BESSELY($x, $ord) { - $x = (is_null($x)) ? 0.0 : self::flattenSingleValue($x); - $ord = (is_null($ord)) ? 0.0 : self::flattenSingleValue($ord); - - if ((is_numeric($x)) && (is_numeric($ord))) { - if (($ord < 0) || ($x == 0.0)) { - return self::$_errorCodes['num']; - } - - switch(floor($ord)) { - case 0 : return self::_Bessely0($x); - break; - case 1 : return self::_Bessely1($x); - break; - default: $fTox = 2 / $x; - $fBym = self::_Bessely0($x); - $fBy = self::_Bessely1($x); - for ($n = 1; $n < $ord; ++$n) { - $fByp = $n * $fTox * $fBy - $fBym; - $fBym = $fBy; - $fBy = $fByp; - } - } - return $fBy; - } - return self::$_errorCodes['value']; - } // function BESSELY() - - - /** - * DELTA - * - * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise. - * - * @param float $a - * @param float $b - * @return int - */ - public static function DELTA($a, $b=0) { - $a = self::flattenSingleValue($a); - $b = self::flattenSingleValue($b); - - return (int) ($a == $b); - } // function DELTA() - - - /** - * GESTEP - * - * Returns 1 if number = step; returns 0 (zero) otherwise - * - * @param float $number - * @param float $step - * @return int - */ - public static function GESTEP($number, $step=0) { - $number = self::flattenSingleValue($number); - $step = self::flattenSingleValue($step); - - return (int) ($number >= $step); - } // function GESTEP() - - - // - // Private method to calculate the erf value - // - private static $_two_sqrtpi = 1.128379167095512574; - - private static function _erfVal($x) { - if (abs($x) > 2.2) { - return 1 - self::_erfcVal($x); - } - $sum = $term = $x; - $xsqr = ($x * $x); - $j = 1; - do { - $term *= $xsqr / $j; - $sum -= $term / (2 * $j + 1); - ++$j; - $term *= $xsqr / $j; - $sum += $term / (2 * $j + 1); - ++$j; - if ($sum == 0.0) { - break; - } - } while (abs($term / $sum) > PRECISION); - return self::$_two_sqrtpi * $sum; - } // function _erfVal() - - - /** - * ERF - * - * Returns the error function integrated between lower_limit and upper_limit - * - * @param float $lower lower bound for integrating ERF - * @param float $upper upper bound for integrating ERF. - * If omitted, ERF integrates between zero and lower_limit - * @return int - */ - public static function ERF($lower, $upper = null) { - $lower = self::flattenSingleValue($lower); - $upper = self::flattenSingleValue($upper); - - if (is_numeric($lower)) { - if ($lower < 0) { - return self::$_errorCodes['num']; - } - if (is_null($upper)) { - return self::_erfVal($lower); - } - if (is_numeric($upper)) { - if ($upper < 0) { - return self::$_errorCodes['num']; - } - return self::_erfVal($upper) - self::_erfVal($lower); - } - } - return self::$_errorCodes['value']; - } // function ERF() - - - // - // Private method to calculate the erfc value - // - private static $_one_sqrtpi = 0.564189583547756287; - - private static function _erfcVal($x) { - if (abs($x) < 2.2) { - return 1 - self::_erfVal($x); - } - if ($x < 0) { - return 2 - self::erfc(-$x); - } - $a = $n = 1; - $b = $c = $x; - $d = ($x * $x) + 0.5; - $q1 = $q2 = $b / $d; - $t = 0; - do { - $t = $a * $n + $b * $x; - $a = $b; - $b = $t; - $t = $c * $n + $d * $x; - $c = $d; - $d = $t; - $n += 0.5; - $q1 = $q2; - $q2 = $b / $d; - } while ((abs($q1 - $q2) / $q2) > PRECISION); - return self::$_one_sqrtpi * exp(-$x * $x) * $q2; - } // function _erfcVal() - - - /** - * ERFC - * - * Returns the complementary ERF function integrated between x and infinity - * - * @param float $x The lower bound for integrating ERF - * @return int - */ - public static function ERFC($x) { - $x = self::flattenSingleValue($x); - - if (is_numeric($x)) { - if ($x < 0) { - return self::$_errorCodes['num']; - } - return self::_erfcVal($x); - } - return self::$_errorCodes['value']; - } // function ERFC() - - - /** - * LOWERCASE - * - * Converts a string value to upper case. - * - * @param string $mixedCaseString - * @return string - */ - public static function LOWERCASE($mixedCaseString) { - $mixedCaseString = self::flattenSingleValue($mixedCaseString); - - if (is_bool($mixedCaseString)) { - $mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE'; - } - - if (function_exists('mb_convert_case')) { - return mb_convert_case($mixedCaseString, MB_CASE_LOWER, 'UTF-8'); - } else { - return strtoupper($mixedCaseString); - } - } // function LOWERCASE() - - - /** - * UPPERCASE - * - * Converts a string value to upper case. - * - * @param string $mixedCaseString - * @return string - */ - public static function UPPERCASE($mixedCaseString) { - $mixedCaseString = self::flattenSingleValue($mixedCaseString); - - if (is_bool($mixedCaseString)) { - $mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE'; - } - - if (function_exists('mb_convert_case')) { - return mb_convert_case($mixedCaseString, MB_CASE_UPPER, 'UTF-8'); - } else { - return strtoupper($mixedCaseString); - } - } // function UPPERCASE() - - - /** - * PROPERCASE - * - * Converts a string value to upper case. - * - * @param string $mixedCaseString - * @return string - */ - public static function PROPERCASE($mixedCaseString) { - $mixedCaseString = self::flattenSingleValue($mixedCaseString); - - if (is_bool($mixedCaseString)) { - $mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE'; - } - - if (function_exists('mb_convert_case')) { - return mb_convert_case($mixedCaseString, MB_CASE_TITLE, 'UTF-8'); - } else { - return ucwords($mixedCaseString); - } - } // function PROPERCASE() - - - /** - * DOLLAR - * - * This function converts a number to text using currency format, with the decimals rounded to the specified place. - * The format used is $#,##0.00_);($#,##0.00).. - * - * @param float $value The value to format - * @param int $decimals The number of digits to display to the right of the decimal point. - * If decimals is negative, number is rounded to the left of the decimal point. - * If you omit decimals, it is assumed to be 2 - * @return string - */ - public static function DOLLAR($value = 0, $decimals = 2) { - $value = self::flattenSingleValue($value); - $decimals = is_null($decimals) ? 0 : self::flattenSingleValue($decimals); - - // Validate parameters - if (!is_numeric($value) || !is_numeric($decimals)) { - return self::$_errorCodes['num']; - } - $decimals = floor($decimals); - - if ($decimals > 0) { - return money_format('%.'.$decimals.'n',$value); - } else { - $round = pow(10,abs($decimals)); - if ($value < 0) { $round = 0-$round; } - $value = self::MROUND($value,$round); - // The implementation of money_format used if the standard PHP function is not available can't handle decimal places of 0, - // so we display to 1 dp and chop off that character and the decimal separator using substr - return substr(money_format('%.1n',$value),0,-2); - } - } // function DOLLAR() - - - /** - * DOLLARDE - * - * Converts a dollar price expressed as an integer part and a fraction part into a dollar price expressed as a decimal number. - * Fractional dollar numbers are sometimes used for security prices. - * - * @param float $fractional_dollar Fractional Dollar - * @param int $fraction Fraction - * @return float - */ - public static function DOLLARDE($fractional_dollar = Null, $fraction = 0) { - $fractional_dollar = self::flattenSingleValue($fractional_dollar); - $fraction = (int)self::flattenSingleValue($fraction); - - // Validate parameters - if (is_null($fractional_dollar) || $fraction < 0) { - return self::$_errorCodes['num']; - } - if ($fraction == 0) { - return self::$_errorCodes['divisionbyzero']; - } - - $dollars = floor($fractional_dollar); - $cents = fmod($fractional_dollar,1); - $cents /= $fraction; - $cents *= pow(10,ceil(log10($fraction))); - return $dollars + $cents; - } // function DOLLARDE() - - - /** - * DOLLARFR - * - * Converts a dollar price expressed as a decimal number into a dollar price expressed as a fraction. - * Fractional dollar numbers are sometimes used for security prices. - * - * @param float $decimal_dollar Decimal Dollar - * @param int $fraction Fraction - * @return float - */ - public static function DOLLARFR($decimal_dollar = Null, $fraction = 0) { - $decimal_dollar = self::flattenSingleValue($decimal_dollar); - $fraction = (int)self::flattenSingleValue($fraction); - - // Validate parameters - if (is_null($decimal_dollar) || $fraction < 0) { - return self::$_errorCodes['num']; - } - if ($fraction == 0) { - return self::$_errorCodes['divisionbyzero']; - } - - $dollars = floor($decimal_dollar); - $cents = fmod($decimal_dollar,1); - $cents *= $fraction; - $cents *= pow(10,-ceil(log10($fraction))); - return $dollars + $cents; - } // function DOLLARFR() - - - /** - * EFFECT - * - * Returns the effective interest rate given the nominal rate and the number of compounding payments per year. - * - * @param float $nominal_rate Nominal interest rate - * @param int $npery Number of compounding payments per year - * @return float - */ - public static function EFFECT($nominal_rate = 0, $npery = 0) { - $nominal_rate = self::flattenSingleValue($nominal_rate); - $npery = (int)self::flattenSingleValue($npery); - - // Validate parameters - if ($nominal_rate <= 0 || $npery < 1) { - return self::$_errorCodes['num']; - } - - return pow((1 + $nominal_rate / $npery), $npery) - 1; - } // function EFFECT() - - - /** - * NOMINAL - * - * Returns the nominal interest rate given the effective rate and the number of compounding payments per year. - * - * @param float $effect_rate Effective interest rate - * @param int $npery Number of compounding payments per year - * @return float - */ - public static function NOMINAL($effect_rate = 0, $npery = 0) { - $effect_rate = self::flattenSingleValue($effect_rate); - $npery = (int)self::flattenSingleValue($npery); - - // Validate parameters - if ($effect_rate <= 0 || $npery < 1) { - return self::$_errorCodes['num']; - } - - // Calculate - return $npery * (pow($effect_rate + 1, 1 / $npery) - 1); - } // function NOMINAL() - - - /** - * PV - * - * Returns the Present Value of a cash flow with constant payments and interest rate (annuities). - * - * @param float $rate Interest rate per period - * @param int $nper Number of periods - * @param float $pmt Periodic payment (annuity) - * @param float $fv Future Value - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0) { - $rate = self::flattenSingleValue($rate); - $nper = self::flattenSingleValue($nper); - $pmt = self::flattenSingleValue($pmt); - $fv = self::flattenSingleValue($fv); - $type = self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - - // Calculate - if (!is_null($rate) && $rate != 0) { - return (-$pmt * (1 + $rate * $type) * ((pow(1 + $rate, $nper) - 1) / $rate) - $fv) / pow(1 + $rate, $nper); - } else { - return -$fv - $pmt * $nper; - } - } // function PV() - - - /** - * FV - * - * Returns the Future Value of a cash flow with constant payments and interest rate (annuities). - * - * @param float $rate Interest rate per period - * @param int $nper Number of periods - * @param float $pmt Periodic payment (annuity) - * @param float $pv Present Value - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0) { - $rate = self::flattenSingleValue($rate); - $nper = self::flattenSingleValue($nper); - $pmt = self::flattenSingleValue($pmt); - $pv = self::flattenSingleValue($pv); - $type = self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - - // Calculate - if (!is_null($rate) && $rate != 0) { - return -$pv * pow(1 + $rate, $nper) - $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate; - } else { - return -$pv - $pmt * $nper; - } - } // function FV() - - - /** - * FVSCHEDULE - * - */ - public static function FVSCHEDULE($principal, $schedule) { - $principal = self::flattenSingleValue($principal); - $schedule = self::flattenArray($schedule); - - foreach($schedule as $n) { - $principal *= 1 + $n; - } - - return $principal; - } // function FVSCHEDULE() - - - /** - * PMT - * - * Returns the constant payment (annuity) for a cash flow with a constant interest rate. - * - * @param float $rate Interest rate per period - * @param int $nper Number of periods - * @param float $pv Present Value - * @param float $fv Future Value - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) { - $rate = self::flattenSingleValue($rate); - $nper = self::flattenSingleValue($nper); - $pv = self::flattenSingleValue($pv); - $fv = self::flattenSingleValue($fv); - $type = self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - - // Calculate - if (!is_null($rate) && $rate != 0) { - return (-$fv - $pv * pow(1 + $rate, $nper)) / (1 + $rate * $type) / ((pow(1 + $rate, $nper) - 1) / $rate); - } else { - return (-$pv - $fv) / $nper; - } - } // function PMT() - - - /** - * NPER - * - * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate. - * - * @param float $rate Interest rate per period - * @param int $pmt Periodic payment (annuity) - * @param float $pv Present Value - * @param float $fv Future Value - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0) { - $rate = self::flattenSingleValue($rate); - $pmt = self::flattenSingleValue($pmt); - $pv = self::flattenSingleValue($pv); - $fv = self::flattenSingleValue($fv); - $type = self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - - // Calculate - if (!is_null($rate) && $rate != 0) { - if ($pmt == 0 && $pv == 0) { - return self::$_errorCodes['num']; - } - return log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate)) / log(1 + $rate); - } else { - if ($pmt == 0) { - return self::$_errorCodes['num']; - } - return (-$pv -$fv) / $pmt; - } - } // function NPER() - - - - private static function _interestAndPrincipal($rate=0, $per=0, $nper=0, $pv=0, $fv=0, $type=0) { - $pmt = self::PMT($rate, $nper, $pv, $fv, $type); - $capital = $pv; - for ($i = 1; $i<= $per; ++$i) { - $interest = ($type && $i == 1)? 0 : -$capital * $rate; - $principal = $pmt - $interest; - $capital += $principal; - } - return array($interest, $principal); - } // function _interestAndPrincipal() - - - /** - * IPMT - * - * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate. - * - * @param float $rate Interest rate per period - * @param int $per Period for which we want to find the interest - * @param int $nper Number of periods - * @param float $pv Present Value - * @param float $fv Future Value - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) { - $rate = self::flattenSingleValue($rate); - $per = (int) self::flattenSingleValue($per); - $nper = (int) self::flattenSingleValue($nper); - $pv = self::flattenSingleValue($pv); - $fv = self::flattenSingleValue($fv); - $type = (int) self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - if ($per <= 0 || $per > $nper) { - return self::$_errorCodes['value']; - } - - // Calculate - $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type); - return $interestAndPrincipal[0]; - } // function IPMT() - - - /** - * CUMIPMT - * - * Returns the cumulative interest paid on a loan between start_period and end_period. - * - * @param float $rate Interest rate per period - * @param int $nper Number of periods - * @param float $pv Present Value - * @param int start The first period in the calculation. - * Payment periods are numbered beginning with 1. - * @param int end The last period in the calculation. - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0) { - $rate = self::flattenSingleValue($rate); - $nper = (int) self::flattenSingleValue($nper); - $pv = self::flattenSingleValue($pv); - $start = (int) self::flattenSingleValue($start); - $end = (int) self::flattenSingleValue($end); - $type = (int) self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - if ($start < 1 || $start > $end) { - return self::$_errorCodes['value']; - } - - // Calculate - $interest = 0; - for ($per = $start; $per <= $end; ++$per) { - $interest += self::IPMT($rate, $per, $nper, $pv, 0, $type); - } - - return $interest; - } // function CUMIPMT() - - - /** - * PPMT - * - * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate. - * - * @param float $rate Interest rate per period - * @param int $per Period for which we want to find the interest - * @param int $nper Number of periods - * @param float $pv Present Value - * @param float $fv Future Value - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) { - $rate = self::flattenSingleValue($rate); - $per = (int) self::flattenSingleValue($per); - $nper = (int) self::flattenSingleValue($nper); - $pv = self::flattenSingleValue($pv); - $fv = self::flattenSingleValue($fv); - $type = (int) self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - if ($per <= 0 || $per > $nper) { - return self::$_errorCodes['value']; - } - - // Calculate - $interestAndPrincipal = self::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type); - return $interestAndPrincipal[1]; - } // function PPMT() - - - /** - * CUMPRINC - * - * Returns the cumulative principal paid on a loan between start_period and end_period. - * - * @param float $rate Interest rate per period - * @param int $nper Number of periods - * @param float $pv Present Value - * @param int start The first period in the calculation. - * Payment periods are numbered beginning with 1. - * @param int end The last period in the calculation. - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period - * @return float - */ - public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0) { - $rate = self::flattenSingleValue($rate); - $nper = (int) self::flattenSingleValue($nper); - $pv = self::flattenSingleValue($pv); - $start = (int) self::flattenSingleValue($start); - $end = (int) self::flattenSingleValue($end); - $type = (int) self::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return self::$_errorCodes['num']; - } - if ($start < 1 || $start > $end) { - return self::$_errorCodes['value']; - } - - // Calculate - $principal = 0; - for ($per = $start; $per <= $end; ++$per) { - $principal += self::PPMT($rate, $per, $nper, $pv, 0, $type); - } - - return $principal; - } // function CUMPRINC() - - - /** - * ISPMT - * - * Returns the interest payment for an investment based on an interest rate and a constant payment schedule. - * - * Excel Function: - * =ISPMT(interest_rate, period, number_payments, PV) - * - * interest_rate is the interest rate for the investment - * - * period is the period to calculate the interest rate. It must be betweeen 1 and number_payments. - * - * number_payments is the number of payments for the annuity - * - * PV is the loan amount or present value of the payments - */ - public static function ISPMT() { - // Return value - $returnValue = 0; - - // Get the parameters - $aArgs = self::flattenArray(func_get_args()); - $interestRate = array_shift($aArgs); - $period = array_shift($aArgs); - $numberPeriods = array_shift($aArgs); - $principleRemaining = array_shift($aArgs); - - // Calculate - $principlePayment = ($principleRemaining * 1.0) / ($numberPeriods * 1.0); - for($i=0; $i <= $period; ++$i) { - $returnValue = $interestRate * $principleRemaining * -1; - $principleRemaining -= $principlePayment; - // principle needs to be 0 after the last payment, don't let floating point screw it up - if($i == $numberPeriods) { - $returnValue = 0; - } - } - return($returnValue); - } // function ISPMT() - - - /** - * NPV - * - * Returns the Net Present Value of a cash flow series given a discount rate. - * - * @param float Discount interest rate - * @param array Cash flow series - * @return float - */ - public static function NPV() { - // Return value - $returnValue = 0; - - // Loop through arguments - $aArgs = self::flattenArray(func_get_args()); - - // Calculate - $rate = array_shift($aArgs); - for ($i = 1; $i <= count($aArgs); ++$i) { - // Is it a numeric value? - if (is_numeric($aArgs[$i - 1])) { - $returnValue += $aArgs[$i - 1] / pow(1 + $rate, $i); - } - } - - // Return - return $returnValue; - } // function NPV() - - - /** - * XNPV - * - * Returns the net present value for a schedule of cash flows that is not necessarily periodic. - * To calculate the net present value for a series of cash flows that is periodic, use the NPV function. - * - * @param float Discount interest rate - * @param array Cash flow series - * @return float - */ - public static function XNPV($rate, $values, $dates) { - if ((!is_array($values)) || (!is_array($dates))) return self::$_errorCodes['value']; - $values = self::flattenArray($values); - $dates = self::flattenArray($dates); - $valCount = count($values); - if ($valCount != count($dates)) return self::$_errorCodes['num']; - - $xnpv = 0.0; - for ($i = 0; $i < $valCount; ++$i) { - $xnpv += $values[$i] / pow(1 + $rate, self::DATEDIF($dates[0],$dates[$i],'d') / 365); - } - return (is_finite($xnpv) ? $xnpv : self::$_errorCodes['value']); - } // function XNPV() - - - public static function IRR($values, $guess = 0.1) { - if (!is_array($values)) return self::$_errorCodes['value']; - $values = self::flattenArray($values); - $guess = self::flattenSingleValue($guess); - - // create an initial range, with a root somewhere between 0 and guess - $x1 = 0.0; - $x2 = $guess; - $f1 = self::NPV($x1, $values); - $f2 = self::NPV($x2, $values); - for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { - if (($f1 * $f2) < 0.0) break; - if (abs($f1) < abs($f2)) { - $f1 = self::NPV($x1 += 1.6 * ($x1 - $x2), $values); - } else { - $f2 = self::NPV($x2 += 1.6 * ($x2 - $x1), $values); - } - } - if (($f1 * $f2) > 0.0) return self::$_errorCodes['value']; - - $f = self::NPV($x1, $values); - if ($f < 0.0) { - $rtb = $x1; - $dx = $x2 - $x1; - } else { - $rtb = $x2; - $dx = $x1 - $x2; - } - - for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { - $dx *= 0.5; - $x_mid = $rtb + $dx; - $f_mid = self::NPV($x_mid, $values); - if ($f_mid <= 0.0) $rtb = $x_mid; - if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) return $x_mid; - } - return self::$_errorCodes['value']; - } // function IRR() - - - public static function MIRR($values, $finance_rate, $reinvestment_rate) { - if (!is_array($values)) return self::$_errorCodes['value']; - $values = self::flattenArray($values); - $finance_rate = self::flattenSingleValue($finance_rate); - $reinvestment_rate = self::flattenSingleValue($reinvestment_rate); - $n = count($values); - - $rr = 1.0 + $reinvestment_rate; - $fr = 1.0 + $finance_rate; - - $npv_pos = $npv_neg = 0.0; - foreach($values as $i => $v) { - if ($v >= 0) { - $npv_pos += $v / pow($rr, $i); - } else { - $npv_neg += $v / pow($fr, $i); - } - } - - if (($npv_neg == 0) || ($npv_pos == 0) || ($reinvestment_rate <= -1)) { - return self::$_errorCodes['value']; - } - - $mirr = pow((-$npv_pos * pow($rr, $n)) - / ($npv_neg * ($rr)), (1.0 / ($n - 1))) - 1.0; - - return (is_finite($mirr) ? $mirr : self::$_errorCodes['value']); - } // function MIRR() - - - public static function XIRR($values, $dates, $guess = 0.1) { - if ((!is_array($values)) && (!is_array($dates))) return self::$_errorCodes['value']; - $values = self::flattenArray($values); - $dates = self::flattenArray($dates); - $guess = self::flattenSingleValue($guess); - if (count($values) != count($dates)) return self::$_errorCodes['num']; - - // create an initial range, with a root somewhere between 0 and guess - $x1 = 0.0; - $x2 = $guess; - $f1 = self::XNPV($x1, $values, $dates); - $f2 = self::XNPV($x2, $values, $dates); - for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { - if (($f1 * $f2) < 0.0) break; - if (abs($f1) < abs($f2)) { - $f1 = self::XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates); - } else { - $f2 = self::XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates); - } - } - if (($f1 * $f2) > 0.0) return self::$_errorCodes['value']; - - $f = self::XNPV($x1, $values, $dates); - if ($f < 0.0) { - $rtb = $x1; - $dx = $x2 - $x1; - } else { - $rtb = $x2; - $dx = $x1 - $x2; - } - - for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) { - $dx *= 0.5; - $x_mid = $rtb + $dx; - $f_mid = self::XNPV($x_mid, $values, $dates); - if ($f_mid <= 0.0) $rtb = $x_mid; - if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) return $x_mid; - } - return self::$_errorCodes['value']; - } - - - /** - * RATE - * - **/ - public static function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) { - $nper = (int) self::flattenSingleValue($nper); - $pmt = self::flattenSingleValue($pmt); - $pv = self::flattenSingleValue($pv); - $fv = (is_null($fv)) ? 0.0 : self::flattenSingleValue($fv); - $type = (is_null($type)) ? 0 : (int) self::flattenSingleValue($type); - $guess = (is_null($guess)) ? 0.1 : self::flattenSingleValue($guess); - - $rate = $guess; - if (abs($rate) < FINANCIAL_PRECISION) { - $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv; - } else { - $f = exp($nper * log(1 + $rate)); - $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv; - } - $y0 = $pv + $pmt * $nper + $fv; - $y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv; - - // find root by secant method - $i = $x0 = 0.0; - $x1 = $rate; - while ((abs($y0 - $y1) > FINANCIAL_PRECISION) && ($i < FINANCIAL_MAX_ITERATIONS)) { - $rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0); - $x0 = $x1; - $x1 = $rate; - - if (abs($rate) < FINANCIAL_PRECISION) { - $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv; - } else { - $f = exp($nper * log(1 + $rate)); - $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv; - } - - $y0 = $y1; - $y1 = $y; - ++$i; - } - return $rate; - } // function RATE() - - - /** - * DB - * - * Returns the depreciation of an asset for a specified period using the fixed-declining balance method. - * This form of depreciation is used if you want to get a higher depreciation value at the beginning of the depreciation - * (as opposed to linear depreciation). The depreciation value is reduced with every depreciation period by the - * depreciation already deducted from the initial cost. - * - * @param float cost Initial cost of the asset. - * @param float salvage Value at the end of the depreciation. (Sometimes called the salvage value of the asset) - * @param int life Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset) - * @param int period The period for which you want to calculate the depreciation. Period must use the same units as life. - * @param float month Number of months in the first year. If month is omitted, it defaults to 12. - * @return float - */ - public static function DB($cost, $salvage, $life, $period, $month=12) { - $cost = (float) self::flattenSingleValue($cost); - $salvage = (float) self::flattenSingleValue($salvage); - $life = (int) self::flattenSingleValue($life); - $period = (int) self::flattenSingleValue($period); - $month = (int) self::flattenSingleValue($month); - - // Validate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) { - if ($cost == 0) { - return 0.0; - } elseif (($cost < 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($month < 1)) { - return self::$_errorCodes['num']; - } - // Set Fixed Depreciation Rate - $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life)); - $fixedDepreciationRate = round($fixedDepreciationRate, 3); - - // Loop through each period calculating the depreciation - $previousDepreciation = 0; - for ($per = 1; $per <= $period; ++$per) { - if ($per == 1) { - $depreciation = $cost * $fixedDepreciationRate * $month / 12; - } elseif ($per == ($life + 1)) { - $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12; - } else { - $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate; - } - $previousDepreciation += $depreciation; - } - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $depreciation = round($depreciation,2); - } - return $depreciation; - } - return self::$_errorCodes['value']; - } // function DB() - - - /** - * DDB - * - * Returns the depreciation of an asset for a specified period using the double-declining balance method or some other method you specify. - * - * @param float cost Initial cost of the asset. - * @param float salvage Value at the end of the depreciation. (Sometimes called the salvage value of the asset) - * @param int life Number of periods over which the asset is depreciated. (Sometimes called the useful life of the asset) - * @param int period The period for which you want to calculate the depreciation. Period must use the same units as life. - * @param float factor The rate at which the balance declines. - * If factor is omitted, it is assumed to be 2 (the double-declining balance method). - * @return float - */ - public static function DDB($cost, $salvage, $life, $period, $factor=2.0) { - $cost = (float) self::flattenSingleValue($cost); - $salvage = (float) self::flattenSingleValue($salvage); - $life = (int) self::flattenSingleValue($life); - $period = (int) self::flattenSingleValue($period); - $factor = (float) self::flattenSingleValue($factor); - - // Validate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) { - if (($cost <= 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($factor <= 0.0) || ($period > $life)) { - return self::$_errorCodes['num']; - } - // Set Fixed Depreciation Rate - $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life)); - $fixedDepreciationRate = round($fixedDepreciationRate, 3); - - // Loop through each period calculating the depreciation - $previousDepreciation = 0; - for ($per = 1; $per <= $period; ++$per) { - $depreciation = min( ($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation) ); - $previousDepreciation += $depreciation; - } - if (self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) { - $depreciation = round($depreciation,2); - } - return $depreciation; - } - return self::$_errorCodes['value']; - } // function DDB() - - - private static function _daysPerYear($year,$basis) { - switch ($basis) { - case 0 : - case 2 : - case 4 : - $daysPerYear = 360; - break; - case 3 : - $daysPerYear = 365; - break; - case 1 : - if (self::_isLeapYear($year)) { - $daysPerYear = 366; - } else { - $daysPerYear = 365; - } - break; - default : - return self::$_errorCodes['num']; - } - return $daysPerYear; - } // function _daysPerYear() - - - /** - * ACCRINT - * - * Returns the discount rate for a security. - * - * @param mixed issue The security's issue date. - * @param mixed firstinter The security's first interest date. - * @param mixed settlement The security's settlement date. - * @param float rate The security's annual coupon rate. - * @param float par The security's par value. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function ACCRINT($issue, $firstinter, $settlement, $rate, $par=1000, $frequency=1, $basis=0) { - $issue = self::flattenSingleValue($issue); - $firstinter = self::flattenSingleValue($firstinter); - $settlement = self::flattenSingleValue($settlement); - $rate = (float) self::flattenSingleValue($rate); - $par = (is_null($par)) ? 1000 : (float) self::flattenSingleValue($par); - $frequency = (is_null($frequency)) ? 1 : (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - // Validate - if ((is_numeric($rate)) && (is_numeric($par))) { - if (($rate <= 0) || ($par <= 0)) { - return self::$_errorCodes['num']; - } - $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - return $daysBetweenIssueAndSettlement; - } - - return $par * $rate * $daysBetweenIssueAndSettlement; - } - return self::$_errorCodes['value']; - } // function ACCRINT() - - - /** - * ACCRINTM - * - * Returns the discount rate for a security. - * - * @param mixed issue The security's issue date. - * @param mixed settlement The security's settlement date. - * @param float rate The security's annual coupon rate. - * @param float par The security's par value. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function ACCRINTM($issue, $settlement, $rate, $par=1000, $basis=0) { - $issue = self::flattenSingleValue($issue); - $settlement = self::flattenSingleValue($settlement); - $rate = (float) self::flattenSingleValue($rate); - $par = (is_null($par)) ? 1000 : (float) self::flattenSingleValue($par); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - // Validate - if ((is_numeric($rate)) && (is_numeric($par))) { - if (($rate <= 0) || ($par <= 0)) { - return self::$_errorCodes['num']; - } - $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - return $daysBetweenIssueAndSettlement; - } - return $par * $rate * $daysBetweenIssueAndSettlement; - } - return self::$_errorCodes['value']; - } // function ACCRINTM() - - - public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) { - $cost = self::flattenSingleValue($cost); - $purchased = self::flattenSingleValue($purchased); - $firstPeriod = self::flattenSingleValue($firstPeriod); - $salvage = self::flattenSingleValue($salvage); - $period = floor(self::flattenSingleValue($period)); - $rate = self::flattenSingleValue($rate); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - $fUsePer = 1.0 / $rate; - - if ($fUsePer < 3.0) { - $amortiseCoeff = 1.0; - } elseif ($fUsePer < 5.0) { - $amortiseCoeff = 1.5; - } elseif ($fUsePer <= 6.0) { - $amortiseCoeff = 2.0; - } else { - $amortiseCoeff = 2.5; - } - - $rate *= $amortiseCoeff; -// $fNRate = floor((self::YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost) + 0.5); - $fNRate = round(self::YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost,0); - $cost -= $fNRate; - $fRest = $cost - $salvage; - - for ($n = 0; $n < $period; ++$n) { -// $fNRate = floor(($rate * $cost) + 0.5); - $fNRate = round($rate * $cost,0); - $fRest -= $fNRate; - - if ($fRest < 0.0) { - switch ($period - $n) { - case 0 : - case 1 : -// return floor(($cost * 0.5) + 0.5); - return round($cost * 0.5,0); - break; - default : return 0.0; - break; - } - } - $cost -= $fNRate; - } - return $fNRate; - } // function AMORDEGRC() - - - public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis=0) { - $cost = self::flattenSingleValue($cost); - $purchased = self::flattenSingleValue($purchased); - $firstPeriod = self::flattenSingleValue($firstPeriod); - $salvage = self::flattenSingleValue($salvage); - $period = self::flattenSingleValue($period); - $rate = self::flattenSingleValue($rate); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - $fOneRate = $cost * $rate; - $fCostDelta = $cost - $salvage; - // Note, quirky variation for leap years on the YEARFRAC for this function - $purchasedYear = self::YEAR($purchased); - $yearFrac = self::YEARFRAC($purchased, $firstPeriod, $basis); - if (($basis == 1) && ($yearFrac < 1) && (self::_isLeapYear($purchasedYear))) { - $yearFrac *= 365 / 366; - } - $f0Rate = $yearFrac * $rate * $cost; - $nNumOfFullPeriods = intval(($cost - $salvage - $f0Rate) / $fOneRate); - - if ($period == 0) { - return $f0Rate; - } elseif ($period <= $nNumOfFullPeriods) { - return $fOneRate; - } elseif ($period == ($nNumOfFullPeriods + 1)) { - return ($fCostDelta - $fOneRate * $nNumOfFullPeriods - $f0Rate); - } else { - return 0.0; - } - } // function AMORLINC() - - - private static function _lastDayOfMonth($testDate) { - $date = clone $testDate; - $date->modify('+1 day'); - return ($date->format('d') == 1); - } // function _lastDayOfMonth() - - private static function _firstDayOfMonth($testDate) { - $date = clone $testDate; - return ($date->format('d') == 1); - } // function _lastDayOfMonth() - - private static function _coupFirstPeriodDate($settlement, $maturity, $frequency, $next) { - $months = 12 / $frequency; - - $result = PHPExcel_Shared_Date::ExcelToPHPObject($maturity); - $eom = self::_lastDayOfMonth($result); - - while ($settlement < PHPExcel_Shared_Date::PHPToExcel($result)) { - $result->modify('-'.$months.' months'); - } - if ($next) { - $result->modify('+'.$months.' months'); - } - - if ($eom) { - $result->modify('-1 day'); - } - - return PHPExcel_Shared_Date::PHPToExcel($result); - } // function _coupFirstPeriodDate() - - - private static function _validFrequency($frequency) { - if (($frequency == 1) || ($frequency == 2) || ($frequency == 4)) { - return true; - } - if ((self::$compatibilityMode == self::COMPATIBILITY_GNUMERIC) && - (($frequency == 6) || ($frequency == 12))) { - return true; - } - return false; - } // function _validFrequency() - - public static function COUPDAYS($settlement, $maturity, $frequency, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $frequency = (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - if (is_string($settlement = self::_getDateValue($settlement))) { - return self::$_errorCodes['value']; - } - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (($settlement > $maturity) || - (!self::_validFrequency($frequency)) || - (($basis < 0) || ($basis > 4))) { - return self::$_errorCodes['num']; - } - - switch ($basis) { - case 3: // Actual/365 - return 365 / $frequency; - case 1: // Actual/actual - if ($frequency == 1) { - $daysPerYear = self::_daysPerYear(self::YEAR($maturity),$basis); - return ($daysPerYear / $frequency); - } else { - $prev = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False); - $next = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); - return ($next - $prev); - } - default: // US (NASD) 30/360, Actual/360 or European 30/360 - return 360 / $frequency; - } - return self::$_errorCodes['value']; - } // function COUPDAYS() - - - public static function COUPDAYBS($settlement, $maturity, $frequency, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $frequency = (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - if (is_string($settlement = self::_getDateValue($settlement))) { - return self::$_errorCodes['value']; - } - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (($settlement > $maturity) || - (!self::_validFrequency($frequency)) || - (($basis < 0) || ($basis > 4))) { - return self::$_errorCodes['num']; - } - - $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis); - $prev = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False); - - return self::YEARFRAC($prev, $settlement, $basis) * $daysPerYear; - } // function COUPDAYBS() - - - public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $frequency = (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - if (is_string($settlement = self::_getDateValue($settlement))) { - return self::$_errorCodes['value']; - } - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (($settlement > $maturity) || - (!self::_validFrequency($frequency)) || - (($basis < 0) || ($basis > 4))) { - return self::$_errorCodes['num']; - } - - $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis); - $next = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); - - return self::YEARFRAC($settlement, $next, $basis) * $daysPerYear; - } // function COUPDAYSNC() - - - public static function COUPNCD($settlement, $maturity, $frequency, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $frequency = (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - if (is_string($settlement = self::_getDateValue($settlement))) { - return self::$_errorCodes['value']; - } - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (($settlement > $maturity) || - (!self::_validFrequency($frequency)) || - (($basis < 0) || ($basis > 4))) { - return self::$_errorCodes['num']; - } - - return self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); - } // function COUPNCD() - - - public static function COUPPCD($settlement, $maturity, $frequency, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $frequency = (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - if (is_string($settlement = self::_getDateValue($settlement))) { - return self::$_errorCodes['value']; - } - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (($settlement > $maturity) || - (!self::_validFrequency($frequency)) || - (($basis < 0) || ($basis > 4))) { - return self::$_errorCodes['num']; - } - - return self::_coupFirstPeriodDate($settlement, $maturity, $frequency, False); - } // function COUPPCD() - - - public static function COUPNUM($settlement, $maturity, $frequency, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $frequency = (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - if (is_string($settlement = self::_getDateValue($settlement))) { - return self::$_errorCodes['value']; - } - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (($settlement > $maturity) || - (!self::_validFrequency($frequency)) || - (($basis < 0) || ($basis > 4))) { - return self::$_errorCodes['num']; - } - - $settlement = self::_coupFirstPeriodDate($settlement, $maturity, $frequency, True); - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis) * 365; - - switch ($frequency) { - case 1: // annual payments - return ceil($daysBetweenSettlementAndMaturity / 360); - case 2: // half-yearly - return ceil($daysBetweenSettlementAndMaturity / 180); - case 4: // quarterly - return ceil($daysBetweenSettlementAndMaturity / 90); - case 6: // bimonthly - return ceil($daysBetweenSettlementAndMaturity / 60); - case 12: // monthly - return ceil($daysBetweenSettlementAndMaturity / 30); - } - return self::$_errorCodes['value']; - } // function COUPNUM() - - - public static function PRICE($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $rate = (float) self::flattenSingleValue($rate); - $yield = (float) self::flattenSingleValue($yield); - $redemption = (float) self::flattenSingleValue($redemption); - $frequency = (int) self::flattenSingleValue($frequency); - $basis = (is_null($basis)) ? 0 : (int) self::flattenSingleValue($basis); - - if (is_string($settlement = self::_getDateValue($settlement))) { - return self::$_errorCodes['value']; - } - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (($settlement > $maturity) || - (!self::_validFrequency($frequency)) || - (($basis < 0) || ($basis > 4))) { - return self::$_errorCodes['num']; - } - - $dsc = self::COUPDAYSNC($settlement, $maturity, $frequency, $basis); - $e = self::COUPDAYS($settlement, $maturity, $frequency, $basis); - $n = self::COUPNUM($settlement, $maturity, $frequency, $basis); - $a = self::COUPDAYBS($settlement, $maturity, $frequency, $basis); - - $baseYF = 1.0 + ($yield / $frequency); - $rfp = 100 * ($rate / $frequency); - $de = $dsc / $e; - - $result = $redemption / pow($baseYF, (--$n + $de)); - for($k = 0; $k <= $n; ++$k) { - $result += $rfp / (pow($baseYF, ($k + $de))); - } - $result -= $rfp * ($a / $e); - - return $result; - } // function PRICE() - - - /** - * DISC - * - * Returns the discount rate for a security. - * - * @param mixed settlement The security's settlement date. - * The security settlement date is the date after the issue date when the security is traded to the buyer. - * @param mixed maturity The security's maturity date. - * The maturity date is the date when the security expires. - * @param int price The security's price per $100 face value. - * @param int redemption the security's redemption value per $100 face value. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function DISC($settlement, $maturity, $price, $redemption, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $price = (float) self::flattenSingleValue($price); - $redemption = (float) self::flattenSingleValue($redemption); - $basis = (int) self::flattenSingleValue($basis); - - // Validate - if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) { - if (($price <= 0) || ($redemption <= 0)) { - return self::$_errorCodes['num']; - } - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - - return ((1 - $price / $redemption) / $daysBetweenSettlementAndMaturity); - } - return self::$_errorCodes['value']; - } // function DISC() - - - /** - * PRICEDISC - * - * Returns the price per $100 face value of a discounted security. - * - * @param mixed settlement The security's settlement date. - * The security settlement date is the date after the issue date when the security is traded to the buyer. - * @param mixed maturity The security's maturity date. - * The maturity date is the date when the security expires. - * @param int discount The security's discount rate. - * @param int redemption The security's redemption value per $100 face value. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $discount = (float) self::flattenSingleValue($discount); - $redemption = (float) self::flattenSingleValue($redemption); - $basis = (int) self::flattenSingleValue($basis); - - // Validate - if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) { - if (($discount <= 0) || ($redemption <= 0)) { - return self::$_errorCodes['num']; - } - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - - return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity); - } - return self::$_errorCodes['value']; - } // function PRICEDISC() - - - /** - * PRICEMAT - * - * Returns the price per $100 face value of a security that pays interest at maturity. - * - * @param mixed settlement The security's settlement date. - * The security's settlement date is the date after the issue date when the security is traded to the buyer. - * @param mixed maturity The security's maturity date. - * The maturity date is the date when the security expires. - * @param mixed issue The security's issue date. - * @param int rate The security's interest rate at date of issue. - * @param int yield The security's annual yield. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $issue = self::flattenSingleValue($issue); - $rate = self::flattenSingleValue($rate); - $yield = self::flattenSingleValue($yield); - $basis = (int) self::flattenSingleValue($basis); - - // Validate - if (is_numeric($rate) && is_numeric($yield)) { - if (($rate <= 0) || ($yield <= 0)) { - return self::$_errorCodes['num']; - } - $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis); - if (!is_numeric($daysPerYear)) { - return $daysPerYear; - } - $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - return $daysBetweenIssueAndSettlement; - } - $daysBetweenIssueAndSettlement *= $daysPerYear; - $daysBetweenIssueAndMaturity = self::YEARFRAC($issue, $maturity, $basis); - if (!is_numeric($daysBetweenIssueAndMaturity)) { - return $daysBetweenIssueAndMaturity; - } - $daysBetweenIssueAndMaturity *= $daysPerYear; - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - $daysBetweenSettlementAndMaturity *= $daysPerYear; - - return ((100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) / - (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) - - (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100)); - } - return self::$_errorCodes['value']; - } // function PRICEMAT() - - - /** - * RECEIVED - * - * Returns the price per $100 face value of a discounted security. - * - * @param mixed settlement The security's settlement date. - * The security settlement date is the date after the issue date when the security is traded to the buyer. - * @param mixed maturity The security's maturity date. - * The maturity date is the date when the security expires. - * @param int investment The amount invested in the security. - * @param int discount The security's discount rate. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $investment = (float) self::flattenSingleValue($investment); - $discount = (float) self::flattenSingleValue($discount); - $basis = (int) self::flattenSingleValue($basis); - - // Validate - if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) { - if (($investment <= 0) || ($discount <= 0)) { - return self::$_errorCodes['num']; - } - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - - return $investment / ( 1 - ($discount * $daysBetweenSettlementAndMaturity)); - } - return self::$_errorCodes['value']; - } // function RECEIVED() - - - /** - * INTRATE - * - * Returns the interest rate for a fully invested security. - * - * @param mixed settlement The security's settlement date. - * The security settlement date is the date after the issue date when the security is traded to the buyer. - * @param mixed maturity The security's maturity date. - * The maturity date is the date when the security expires. - * @param int investment The amount invested in the security. - * @param int redemption The amount to be received at maturity. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $investment = (float) self::flattenSingleValue($investment); - $redemption = (float) self::flattenSingleValue($redemption); - $basis = (int) self::flattenSingleValue($basis); - - // Validate - if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) { - if (($investment <= 0) || ($redemption <= 0)) { - return self::$_errorCodes['num']; - } - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - - return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity); - } - return self::$_errorCodes['value']; - } // function INTRATE() - - - /** - * TBILLEQ - * - * Returns the bond-equivalent yield for a Treasury bill. - * - * @param mixed settlement The Treasury bill's settlement date. - * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. - * @param mixed maturity The Treasury bill's maturity date. - * The maturity date is the date when the Treasury bill expires. - * @param int discount The Treasury bill's discount rate. - * @return float - */ - public static function TBILLEQ($settlement, $maturity, $discount) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $discount = self::flattenSingleValue($discount); - - // Use TBILLPRICE for validation - $testValue = self::TBILLPRICE($settlement, $maturity, $discount); - if (is_string($testValue)) { - return $testValue; - } - - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - ++$maturity; - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity) * 360; - } else { - $daysBetweenSettlementAndMaturity = (self::_getDateValue($maturity) - self::_getDateValue($settlement)); - } - - return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity); - } // function TBILLEQ() - - - /** - * TBILLPRICE - * - * Returns the yield for a Treasury bill. - * - * @param mixed settlement The Treasury bill's settlement date. - * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. - * @param mixed maturity The Treasury bill's maturity date. - * The maturity date is the date when the Treasury bill expires. - * @param int discount The Treasury bill's discount rate. - * @return float - */ - public static function TBILLPRICE($settlement, $maturity, $discount) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $discount = self::flattenSingleValue($discount); - - if (is_string($maturity = self::_getDateValue($maturity))) { - return self::$_errorCodes['value']; - } - - // Validate - if (is_numeric($discount)) { - if ($discount <= 0) { - return self::$_errorCodes['num']; - } - - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - ++$maturity; - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity) * 360; - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - } else { - $daysBetweenSettlementAndMaturity = (self::_getDateValue($maturity) - self::_getDateValue($settlement)); - } - - if ($daysBetweenSettlementAndMaturity > 360) { - return self::$_errorCodes['num']; - } - - $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360)); - if ($price <= 0) { - return self::$_errorCodes['num']; - } - return $price; - } - return self::$_errorCodes['value']; - } // function TBILLPRICE() - - - /** - * TBILLYIELD - * - * Returns the yield for a Treasury bill. - * - * @param mixed settlement The Treasury bill's settlement date. - * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. - * @param mixed maturity The Treasury bill's maturity date. - * The maturity date is the date when the Treasury bill expires. - * @param int price The Treasury bill's price per $100 face value. - * @return float - */ - public static function TBILLYIELD($settlement, $maturity, $price) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $price = self::flattenSingleValue($price); - - // Validate - if (is_numeric($price)) { - if ($price <= 0) { - return self::$_errorCodes['num']; - } - - if (self::$compatibilityMode == self::COMPATIBILITY_OPENOFFICE) { - ++$maturity; - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity) * 360; - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - } else { - $daysBetweenSettlementAndMaturity = (self::_getDateValue($maturity) - self::_getDateValue($settlement)); - } - - if ($daysBetweenSettlementAndMaturity > 360) { - return self::$_errorCodes['num']; - } - - return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity); - } - return self::$_errorCodes['value']; - } // function TBILLYIELD() - - - /** - * SLN - * - * Returns the straight-line depreciation of an asset for one period - * - * @param cost Initial cost of the asset - * @param salvage Value at the end of the depreciation - * @param life Number of periods over which the asset is depreciated - * @return float - */ - public static function SLN($cost, $salvage, $life) { - $cost = self::flattenSingleValue($cost); - $salvage = self::flattenSingleValue($salvage); - $life = self::flattenSingleValue($life); - - // Calculate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) { - if ($life < 0) { - return self::$_errorCodes['num']; - } - return ($cost - $salvage) / $life; - } - return self::$_errorCodes['value']; - } // function SLN() - - - /** - * YIELDMAT - * - * Returns the annual yield of a security that pays interest at maturity. - * - * @param mixed settlement The security's settlement date. - * The security's settlement date is the date after the issue date when the security is traded to the buyer. - * @param mixed maturity The security's maturity date. - * The maturity date is the date when the security expires. - * @param mixed issue The security's issue date. - * @param int rate The security's interest rate at date of issue. - * @param int price The security's price per $100 face value. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $issue = self::flattenSingleValue($issue); - $rate = self::flattenSingleValue($rate); - $price = self::flattenSingleValue($price); - $basis = (int) self::flattenSingleValue($basis); - - // Validate - if (is_numeric($rate) && is_numeric($price)) { - if (($rate <= 0) || ($price <= 0)) { - return self::$_errorCodes['num']; - } - $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis); - if (!is_numeric($daysPerYear)) { - return $daysPerYear; - } - $daysBetweenIssueAndSettlement = self::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - return $daysBetweenIssueAndSettlement; - } - $daysBetweenIssueAndSettlement *= $daysPerYear; - $daysBetweenIssueAndMaturity = self::YEARFRAC($issue, $maturity, $basis); - if (!is_numeric($daysBetweenIssueAndMaturity)) { - return $daysBetweenIssueAndMaturity; - } - $daysBetweenIssueAndMaturity *= $daysPerYear; - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - $daysBetweenSettlementAndMaturity *= $daysPerYear; - - return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) / - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) * - ($daysPerYear / $daysBetweenSettlementAndMaturity); - } - return self::$_errorCodes['value']; - } // function YIELDMAT() - - - /** - * YIELDDISC - * - * Returns the annual yield of a security that pays interest at maturity. - * - * @param mixed settlement The security's settlement date. - * The security's settlement date is the date after the issue date when the security is traded to the buyer. - * @param mixed maturity The security's maturity date. - * The maturity date is the date when the security expires. - * @param int price The security's price per $100 face value. - * @param int redemption The security's redemption value per $100 face value. - * @param int basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @return float - */ - public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis=0) { - $settlement = self::flattenSingleValue($settlement); - $maturity = self::flattenSingleValue($maturity); - $price = self::flattenSingleValue($price); - $redemption = self::flattenSingleValue($redemption); - $basis = (int) self::flattenSingleValue($basis); - - // Validate - if (is_numeric($price) && is_numeric($redemption)) { - if (($price <= 0) || ($redemption <= 0)) { - return self::$_errorCodes['num']; - } - $daysPerYear = self::_daysPerYear(self::YEAR($settlement),$basis); - if (!is_numeric($daysPerYear)) { - return $daysPerYear; - } - $daysBetweenSettlementAndMaturity = self::YEARFRAC($settlement, $maturity,$basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - return $daysBetweenSettlementAndMaturity; - } - $daysBetweenSettlementAndMaturity *= $daysPerYear; - - return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity); - } - return self::$_errorCodes['value']; - } // function YIELDDISC() - - - /** - * CELL_ADDRESS - * - * Creates a cell address as text, given specified row and column numbers. - * - * @param row Row number to use in the cell reference - * @param column Column number to use in the cell reference - * @param relativity Flag indicating the type of reference to return - * 1 or omitted Absolute - * 2 Absolute row; relative column - * 3 Relative row; absolute column - * 4 Relative - * @param referenceStyle A logical value that specifies the A1 or R1C1 reference style. - * TRUE or omitted CELL_ADDRESS returns an A1-style reference - * FALSE CELL_ADDRESS returns an R1C1-style reference - * @param sheetText Optional Name of worksheet to use - * @return string - */ - public static function CELL_ADDRESS($row, $column, $relativity=1, $referenceStyle=True, $sheetText='') { - $row = self::flattenSingleValue($row); - $column = self::flattenSingleValue($column); - $relativity = self::flattenSingleValue($relativity); - $sheetText = self::flattenSingleValue($sheetText); - - if (($row < 1) || ($column < 1)) { - return self::$_errorCodes['value']; - } - - if ($sheetText > '') { - if (strpos($sheetText,' ') !== False) { $sheetText = "'".$sheetText."'"; } - $sheetText .='!'; - } - if ((!is_bool($referenceStyle)) || $referenceStyle) { - $rowRelative = $columnRelative = '$'; - $column = PHPExcel_Cell::stringFromColumnIndex($column-1); - if (($relativity == 2) || ($relativity == 4)) { $columnRelative = ''; } - if (($relativity == 3) || ($relativity == 4)) { $rowRelative = ''; } - return $sheetText.$columnRelative.$column.$rowRelative.$row; - } else { - if (($relativity == 2) || ($relativity == 4)) { $column = '['.$column.']'; } - if (($relativity == 3) || ($relativity == 4)) { $row = '['.$row.']'; } - return $sheetText.'R'.$row.'C'.$column; - } - } // function CELL_ADDRESS() - - - /** - * COLUMN - * - * Returns the column number of the given cell reference - * If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array. - * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the - * reference of the cell in which the COLUMN function appears; otherwise this function returns 0. - * - * @param cellAddress A reference to a range of cells for which you want the column numbers - * @return integer or array of integer - */ - public static function COLUMN($cellAddress=Null) { - if (is_null($cellAddress) || trim($cellAddress) === '') { return 0; } - - if (is_array($cellAddress)) { - foreach($cellAddress as $columnKey => $value) { - $columnKey = preg_replace('/[^a-z]/i','',$columnKey); - return (integer) PHPExcel_Cell::columnIndexFromString($columnKey); - } - } else { - if (strpos($cellAddress,'!') !== false) { - list($sheet,$cellAddress) = explode('!',$cellAddress); - } - if (strpos($cellAddress,':') !== false) { - list($startAddress,$endAddress) = explode(':',$cellAddress); - $startAddress = preg_replace('/[^a-z]/i','',$startAddress); - $endAddress = preg_replace('/[^a-z]/i','',$endAddress); - $returnValue = array(); - do { - $returnValue[] = (integer) PHPExcel_Cell::columnIndexFromString($startAddress); - } while ($startAddress++ != $endAddress); - return $returnValue; - } else { - $cellAddress = preg_replace('/[^a-z]/i','',$cellAddress); - return (integer) PHPExcel_Cell::columnIndexFromString($cellAddress); - } - } - } // function COLUMN() - - - /** - * COLUMNS - * - * Returns the number of columns in an array or reference. - * - * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of columns - * @return integer - */ - public static function COLUMNS($cellAddress=Null) { - if (is_null($cellAddress) || $cellAddress === '') { - return 1; - } elseif (!is_array($cellAddress)) { - return self::$_errorCodes['value']; - } - - $x = array_keys($cellAddress); - $x = array_shift($x); - $isMatrix = (is_numeric($x)); - list($columns,$rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress); - - if ($isMatrix) { - return $rows; - } else { - return $columns; - } - } // function COLUMNS() - - - /** - * ROW - * - * Returns the row number of the given cell reference - * If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array. - * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the - * reference of the cell in which the ROW function appears; otherwise this function returns 0. - * - * @param cellAddress A reference to a range of cells for which you want the row numbers - * @return integer or array of integer - */ - public static function ROW($cellAddress=Null) { - if (is_null($cellAddress) || trim($cellAddress) === '') { return 0; } - - if (is_array($cellAddress)) { - foreach($cellAddress as $columnKey => $rowValue) { - foreach($rowValue as $rowKey => $cellValue) { - return (integer) preg_replace('/[^0-9]/i','',$rowKey); - } - } - } else { - if (strpos($cellAddress,'!') !== false) { - list($sheet,$cellAddress) = explode('!',$cellAddress); - } - if (strpos($cellAddress,':') !== false) { - list($startAddress,$endAddress) = explode(':',$cellAddress); - $startAddress = preg_replace('/[^0-9]/','',$startAddress); - $endAddress = preg_replace('/[^0-9]/','',$endAddress); - $returnValue = array(); - do { - $returnValue[][] = (integer) $startAddress; - } while ($startAddress++ != $endAddress); - return $returnValue; - } else { - list($cellAddress) = explode(':',$cellAddress); - return (integer) preg_replace('/[^0-9]/','',$cellAddress); - } - } - } // function ROW() - - - /** - * ROWS - * - * Returns the number of rows in an array or reference. - * - * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows - * @return integer - */ - public static function ROWS($cellAddress=Null) { - if (is_null($cellAddress) || $cellAddress === '') { - return 1; - } elseif (!is_array($cellAddress)) { - return self::$_errorCodes['value']; - } - - $i = array_keys($cellAddress); - $isMatrix = (is_numeric(array_shift($i))); - list($columns,$rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress); - - if ($isMatrix) { - return $columns; - } else { - return $rows; - } - } // function ROWS() - - - /** - * INDIRECT - * - * Returns the number of rows in an array or reference. - * - * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows - * @return integer - */ - public static function INDIRECT($cellAddress=Null, PHPExcel_Cell $pCell = null) { - $cellAddress = self::flattenSingleValue($cellAddress); - if (is_null($cellAddress) || $cellAddress === '') { - return self::REF(); - } - - $cellAddress1 = $cellAddress; - $cellAddress2 = NULL; - if (strpos($cellAddress,':') !== false) { - list($cellAddress1,$cellAddress2) = explode(':',$cellAddress); - } - - if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress1, $matches)) || - ((!is_null($cellAddress2)) && (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress2, $matches)))) { - return self::REF(); - } - - if (strpos($cellAddress,'!') !== false) { - list($sheetName,$cellAddress) = explode('!',$cellAddress); - $pSheet = $pCell->getParent()->getParent()->getSheetByName($sheetName); - } else { - $pSheet = $pCell->getParent(); - } - - return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, False); - } // function INDIRECT() - - - /** - * OFFSET - * - * Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells. - * The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and - * the number of columns to be returned. - * - * @param cellAddress The reference from which you want to base the offset. Reference must refer to a cell or - * range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value. - * @param rows The number of rows, up or down, that you want the upper-left cell to refer to. - * Using 5 as the rows argument specifies that the upper-left cell in the reference is - * five rows below reference. Rows can be positive (which means below the starting reference) - * or negative (which means above the starting reference). - * @param cols The number of columns, to the left or right, that you want the upper-left cell of the result - * to refer to. Using 5 as the cols argument specifies that the upper-left cell in the - * reference is five columns to the right of reference. Cols can be positive (which means - * to the right of the starting reference) or negative (which means to the left of the - * starting reference). - * @param height The height, in number of rows, that you want the returned reference to be. Height must be a positive number. - * @param width The width, in number of columns, that you want the returned reference to be. Width must be a positive number. - * @return string A reference to a cell or range of cells - */ - public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null) { - $rows = self::flattenSingleValue($rows); - $columns = self::flattenSingleValue($columns); - $height = self::flattenSingleValue($height); - $width = self::flattenSingleValue($width); - if ($cellAddress == Null) { - return 0; - } - - $args = func_get_args(); - $pCell = array_pop($args); - if (!is_object($pCell)) { - return self::$_errorCodes['reference']; - } - - $sheetName = null; - if (strpos($cellAddress,"!")) { - list($sheetName,$cellAddress) = explode("!",$cellAddress); - } - if (strpos($cellAddress,":")) { - list($startCell,$endCell) = explode(":",$cellAddress); - } else { - $startCell = $endCell = $cellAddress; - } - list($startCellColumn,$startCellRow) = PHPExcel_Cell::coordinateFromString($startCell); - list($endCellColumn,$endCellRow) = PHPExcel_Cell::coordinateFromString($endCell); - - $startCellRow += $rows; - $startCellColumn = PHPExcel_Cell::columnIndexFromString($startCellColumn) - 1; - $startCellColumn += $columns; - - if (($startCellRow <= 0) || ($startCellColumn < 0)) { - return self::$_errorCodes['reference']; - } - $endCellColumn = PHPExcel_Cell::columnIndexFromString($endCellColumn) - 1; - if (($width != null) && (!is_object($width))) { - $endCellColumn = $startCellColumn + $width - 1; - } else { - $endCellColumn += $columns; - } - $startCellColumn = PHPExcel_Cell::stringFromColumnIndex($startCellColumn); - - if (($height != null) && (!is_object($height))) { - $endCellRow = $startCellRow + $height - 1; - } else { - $endCellRow += $rows; - } - - if (($endCellRow <= 0) || ($endCellColumn < 0)) { - return self::$_errorCodes['reference']; - } - $endCellColumn = PHPExcel_Cell::stringFromColumnIndex($endCellColumn); - - $cellAddress = $startCellColumn.$startCellRow; - if (($startCellColumn != $endCellColumn) || ($startCellRow != $endCellRow)) { - $cellAddress .= ':'.$endCellColumn.$endCellRow; - } - - if ($sheetName !== null) { - $pSheet = $pCell->getParent()->getParent()->getSheetByName($sheetName); - } else { - $pSheet = $pCell->getParent(); - } - - return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, False); - } // function OFFSET() - - - public static function CHOOSE() { - $chooseArgs = func_get_args(); - $chosenEntry = self::flattenArray(array_shift($chooseArgs)); - $entryCount = count($chooseArgs) - 1; - - if(is_array($chosenEntry)) { - $chosenEntry = array_shift($chosenEntry); - } - if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) { - --$chosenEntry; - } else { - return self::$_errorCodes['value']; - } - $chosenEntry = floor($chosenEntry); - if (($chosenEntry <= 0) || ($chosenEntry > $entryCount)) { - return self::$_errorCodes['value']; - } - - if (is_array($chooseArgs[$chosenEntry])) { - return self::flattenArray($chooseArgs[$chosenEntry]); - } else { - return $chooseArgs[$chosenEntry]; - } - } // function CHOOSE() - - - /** - * MATCH - * - * The MATCH function searches for a specified item in a range of cells - * - * @param lookup_value The value that you want to match in lookup_array - * @param lookup_array The range of cells being searched - * @param match_type The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered. - * @return integer The relative position of the found item - */ - public static function MATCH($lookup_value, $lookup_array, $match_type=1) { - $lookup_array = self::flattenArray($lookup_array); - $lookup_value = self::flattenSingleValue($lookup_value); - $match_type = (is_null($match_type)) ? 1 : (int) self::flattenSingleValue($match_type); - // MATCH is not case sensitive - $lookup_value = strtolower($lookup_value); - - // lookup_value type has to be number, text, or logical values - if ((!is_numeric($lookup_value)) && (!is_string($lookup_value)) && (!is_bool($lookup_value))) { - return self::$_errorCodes['na']; - } - - // match_type is 0, 1 or -1 - if (($match_type !== 0) && ($match_type !== -1) && ($match_type !== 1)) { - return self::$_errorCodes['na']; - } - - // lookup_array should not be empty - $lookupArraySize = count($lookup_array); - if ($lookupArraySize <= 0) { - return self::$_errorCodes['na']; - } - - // lookup_array should contain only number, text, or logical values, or empty (null) cells - foreach($lookup_array as $i => $lookupArrayValue) { - // check the type of the value - if ((!is_numeric($lookupArrayValue)) && (!is_string($lookupArrayValue)) && - (!is_bool($lookupArrayValue)) && (!is_null($lookupArrayValue))) { - return self::$_errorCodes['na']; - } - // convert strings to lowercase for case-insensitive testing - if (is_string($lookupArrayValue)) { - $lookup_array[$i] = strtolower($lookupArrayValue); - } - if ((is_null($lookupArrayValue)) && (($match_type == 1) || ($match_type == -1))) { - $lookup_array = array_slice($lookup_array,0,$i-1); - } - } - - // if match_type is 1 or -1, the list has to be ordered - if ($match_type == 1) { - asort($lookup_array); - $keySet = array_keys($lookup_array); - } elseif($match_type == -1) { - arsort($lookup_array); - $keySet = array_keys($lookup_array); - } - - // ** - // find the match - // ** - // loop on the cells -// var_dump($lookup_array); -// echo '
'; - foreach($lookup_array as $i => $lookupArrayValue) { - if (($match_type == 0) && ($lookupArrayValue == $lookup_value)) { - // exact match - return ++$i; - } elseif (($match_type == -1) && ($lookupArrayValue <= $lookup_value)) { -// echo '$i = '.$i.' => '; -// var_dump($lookupArrayValue); -// echo '
'; -// echo 'Keyset = '; -// var_dump($keySet); -// echo '
'; - $i = array_search($i,$keySet); -// echo '$i='.$i.'
'; - // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value - if ($i < 1){ - // 1st cell was allready smaller than the lookup_value - break; - } else { - // the previous cell was the match - return $keySet[$i-1]+1; - } - } elseif (($match_type == 1) && ($lookupArrayValue >= $lookup_value)) { -// echo '$i = '.$i.' => '; -// var_dump($lookupArrayValue); -// echo '
'; -// echo 'Keyset = '; -// var_dump($keySet); -// echo '
'; - $i = array_search($i,$keySet); -// echo '$i='.$i.'
'; - // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value - if ($i < 1){ - // 1st cell was allready bigger than the lookup_value - break; - } else { - // the previous cell was the match - return $keySet[$i-1]+1; - } - } - } - - // unsuccessful in finding a match, return #N/A error value - return self::$_errorCodes['na']; - } // function MATCH() - - - /** - * INDEX - * - * Uses an index to choose a value from a reference or array - * implemented: Return the value of a specified cell or array of cells Array form - * not implemented: Return a reference to specified cells Reference form - * - * @param range_array a range of cells or an array constant - * @param row_num selects the row in array from which to return a value. If row_num is omitted, column_num is required. - * @param column_num selects the column in array from which to return a value. If column_num is omitted, row_num is required. - */ - public static function INDEX($arrayValues,$rowNum = 0,$columnNum = 0) { - - if (($rowNum < 0) || ($columnNum < 0)) { - return self::$_errorCodes['value']; - } - - if (!is_array($arrayValues)) { - return self::$_errorCodes['reference']; - } - - $rowKeys = array_keys($arrayValues); - $columnKeys = @array_keys($arrayValues[$rowKeys[0]]); - - if ($columnNum > count($columnKeys)) { - return self::$_errorCodes['value']; - } elseif ($columnNum == 0) { - if ($rowNum == 0) { - return $arrayValues; - } - $rowNum = $rowKeys[--$rowNum]; - $returnArray = array(); - foreach($arrayValues as $arrayColumn) { - if (is_array($arrayColumn)) { - if (isset($arrayColumn[$rowNum])) { - $returnArray[] = $arrayColumn[$rowNum]; - } else { - return $arrayValues[$rowNum]; - } - } else { - return $arrayValues[$rowNum]; - } - } - return $returnArray; - } - $columnNum = $columnKeys[--$columnNum]; - if ($rowNum > count($rowKeys)) { - return self::$_errorCodes['value']; - } elseif ($rowNum == 0) { - return $arrayValues[$columnNum]; - } - $rowNum = $rowKeys[--$rowNum]; - - return $arrayValues[$rowNum][$columnNum]; - } // function INDEX() - - /** * N * @@ -11385,435 +579,6 @@ class PHPExcel_Calculation_Functions { } // function TYPE() - /** - * SYD - * - * Returns the sum-of-years' digits depreciation of an asset for a specified period. - * - * @param cost Initial cost of the asset - * @param salvage Value at the end of the depreciation - * @param life Number of periods over which the asset is depreciated - * @param period Period - * @return float - */ - public static function SYD($cost, $salvage, $life, $period) { - $cost = self::flattenSingleValue($cost); - $salvage = self::flattenSingleValue($salvage); - $life = self::flattenSingleValue($life); - $period = self::flattenSingleValue($period); - - // Calculate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) { - if (($life < 1) || ($period > $life)) { - return self::$_errorCodes['num']; - } - return (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1)); - } - return self::$_errorCodes['value']; - } // function SYD() - - - /** - * TRANSPOSE - * - * @param array $matrixData A matrix of values - * @return array - * - * Unlike the Excel TRANSPOSE function, which will only work on a single row or column, this function will transpose a full matrix. - */ - public static function TRANSPOSE($matrixData) { - $returnMatrix = array(); - if (!is_array($matrixData)) { $matrixData = array(array($matrixData)); } - - $column = 0; - foreach($matrixData as $matrixRow) { - $row = 0; - foreach($matrixRow as $matrixCell) { - $returnMatrix[$row][$column] = $matrixCell; - ++$row; - } - ++$column; - } - return $returnMatrix; - } // function TRANSPOSE() - - - /** - * MMULT - * - * @param array $matrixData1 A matrix of values - * @param array $matrixData2 A matrix of values - * @return array - */ - public static function MMULT($matrixData1,$matrixData2) { - $matrixAData = $matrixBData = array(); - if (!is_array($matrixData1)) { $matrixData1 = array(array($matrixData1)); } - if (!is_array($matrixData2)) { $matrixData2 = array(array($matrixData2)); } - - $rowA = 0; - foreach($matrixData1 as $matrixRow) { - $columnA = 0; - foreach($matrixRow as $matrixCell) { - if ((is_string($matrixCell)) || ($matrixCell === null)) { - return self::$_errorCodes['value']; - } - $matrixAData[$rowA][$columnA] = $matrixCell; - ++$columnA; - } - ++$rowA; - } - try { - $matrixA = new Matrix($matrixAData); - $rowB = 0; - foreach($matrixData2 as $matrixRow) { - $columnB = 0; - foreach($matrixRow as $matrixCell) { - if ((is_string($matrixCell)) || ($matrixCell === null)) { - return self::$_errorCodes['value']; - } - $matrixBData[$rowB][$columnB] = $matrixCell; - ++$columnB; - } - ++$rowB; - } - $matrixB = new Matrix($matrixBData); - - if (($rowA != $columnB) || ($rowB != $columnA)) { - return self::$_errorCodes['value']; - } - - return $matrixA->times($matrixB)->getArray(); - } catch (Exception $ex) { - return self::$_errorCodes['value']; - } - } // function MMULT() - - - /** - * MINVERSE - * - * @param array $matrixValues A matrix of values - * @return array - */ - public static function MINVERSE($matrixValues) { - $matrixData = array(); - if (!is_array($matrixValues)) { $matrixValues = array(array($matrixValues)); } - - $row = $maxColumn = 0; - foreach($matrixValues as $matrixRow) { - $column = 0; - foreach($matrixRow as $matrixCell) { - if ((is_string($matrixCell)) || ($matrixCell === null)) { - return self::$_errorCodes['value']; - } - $matrixData[$column][$row] = $matrixCell; - ++$column; - } - if ($column > $maxColumn) { $maxColumn = $column; } - ++$row; - } - if ($row != $maxColumn) { return self::$_errorCodes['value']; } - - try { - $matrix = new Matrix($matrixData); - return $matrix->inverse()->getArray(); - } catch (Exception $ex) { - return self::$_errorCodes['value']; - } - } // function MINVERSE() - - - /** - * MDETERM - * - * @param array $matrixValues A matrix of values - * @return float - */ - public static function MDETERM($matrixValues) { - $matrixData = array(); - if (!is_array($matrixValues)) { $matrixValues = array(array($matrixValues)); } - - $row = $maxColumn = 0; - foreach($matrixValues as $matrixRow) { - $column = 0; - foreach($matrixRow as $matrixCell) { - if ((is_string($matrixCell)) || ($matrixCell === null)) { - return self::$_errorCodes['value']; - } - $matrixData[$column][$row] = $matrixCell; - ++$column; - } - if ($column > $maxColumn) { $maxColumn = $column; } - ++$row; - } - if ($row != $maxColumn) { return self::$_errorCodes['value']; } - - try { - $matrix = new Matrix($matrixData); - return $matrix->det(); - } catch (Exception $ex) { - return self::$_errorCodes['value']; - } - } // function MDETERM() - - - /** - * SUMPRODUCT - * - * @param mixed $value Value to check - * @return float - */ - public static function SUMPRODUCT() { - $arrayList = func_get_args(); - - $wrkArray = self::flattenArray(array_shift($arrayList)); - $wrkCellCount = count($wrkArray); - - foreach($arrayList as $matrixData) { - $array2 = self::flattenArray($matrixData); - $count = count($array2); - if ($wrkCellCount != $count) { - return self::$_errorCodes['value']; - } - - foreach ($array2 as $i => $val) { - if (((is_numeric($wrkArray[$i])) && (!is_string($wrkArray[$i]))) && - ((is_numeric($val)) && (!is_string($val)))) { - $wrkArray[$i] *= $val; - } - } - } - - return array_sum($wrkArray); - } // function SUMPRODUCT() - - - /** - * SUMX2MY2 - * - * @param mixed $value Value to check - * @return float - */ - public static function SUMX2MY2($matrixData1,$matrixData2) { - $array1 = self::flattenArray($matrixData1); - $array2 = self::flattenArray($matrixData2); - $count1 = count($array1); - $count2 = count($array2); - if ($count1 < $count2) { - $count = $count1; - } else { - $count = $count2; - } - - $result = 0; - for ($i = 0; $i < $count; ++$i) { - if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && - ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) { - $result += ($array1[$i] * $array1[$i]) - ($array2[$i] * $array2[$i]); - } - } - - return $result; - } // function SUMX2MY2() - - - /** - * SUMX2PY2 - * - * @param mixed $value Value to check - * @return float - */ - public static function SUMX2PY2($matrixData1,$matrixData2) { - $array1 = self::flattenArray($matrixData1); - $array2 = self::flattenArray($matrixData2); - $count1 = count($array1); - $count2 = count($array2); - if ($count1 < $count2) { - $count = $count1; - } else { - $count = $count2; - } - - $result = 0; - for ($i = 0; $i < $count; ++$i) { - if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && - ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) { - $result += ($array1[$i] * $array1[$i]) + ($array2[$i] * $array2[$i]); - } - } - - return $result; - } // function SUMX2PY2() - - - /** - * SUMXMY2 - * - * @param mixed $value Value to check - * @return float - */ - public static function SUMXMY2($matrixData1,$matrixData2) { - $array1 = self::flattenArray($matrixData1); - $array2 = self::flattenArray($matrixData2); - $count1 = count($array1); - $count2 = count($array2); - if ($count1 < $count2) { - $count = $count1; - } else { - $count = $count2; - } - - $result = 0; - for ($i = 0; $i < $count; ++$i) { - if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && - ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) { - $result += ($array1[$i] - $array2[$i]) * ($array1[$i] - $array2[$i]); - } - } - - return $result; - } // function SUMXMY2() - - - private static function _vlookupSort($a,$b) { - $f = array_keys($a); - $firstColumn = array_shift($f); - if (strtolower($a[$firstColumn]) == strtolower($b[$firstColumn])) { - return 0; - } - return (strtolower($a[$firstColumn]) < strtolower($b[$firstColumn])) ? -1 : 1; - } // function _vlookupSort() - - - /** - * VLOOKUP - * The VLOOKUP function searches for value in the left-most column of lookup_array and returns the value in the same row based on the index_number. - * @param lookup_value The value that you want to match in lookup_array - * @param lookup_array The range of cells being searched - * @param index_number The column number in table_array from which the matching value must be returned. The first column is 1. - * @param not_exact_match Determines if you are looking for an exact match based on lookup_value. - * @return mixed The value of the found cell - */ - public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match=true) { - $lookup_value = self::flattenSingleValue($lookup_value); - $index_number = self::flattenSingleValue($index_number); - $not_exact_match = self::flattenSingleValue($not_exact_match); - - // index_number must be greater than or equal to 1 - if ($index_number < 1) { - return self::$_errorCodes['value']; - } - - // index_number must be less than or equal to the number of columns in lookup_array - if ((!is_array($lookup_array)) || (count($lookup_array) < 1)) { - return self::$_errorCodes['reference']; - } else { - $f = array_keys($lookup_array); - $firstRow = array_pop($f); - if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array[$firstRow]))) { - return self::$_errorCodes['reference']; - } else { - $columnKeys = array_keys($lookup_array[$firstRow]); - $returnColumn = $columnKeys[--$index_number]; - $firstColumn = array_shift($columnKeys); - } - } - - if (!$not_exact_match) { - uasort($lookup_array,array('self','_vlookupSort')); - } - - $rowNumber = $rowValue = False; - foreach($lookup_array as $rowKey => $rowData) { - if (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)) { - break; - } - $rowNumber = $rowKey; - $rowValue = $rowData[$firstColumn]; - } - - if ($rowNumber !== false) { - if ((!$not_exact_match) && ($rowValue != $lookup_value)) { - // if an exact match is required, we have what we need to return an appropriate response - return self::$_errorCodes['na']; - } else { - // otherwise return the appropriate value - return $lookup_array[$rowNumber][$returnColumn]; - } - } - - return self::$_errorCodes['na']; - } // function VLOOKUP() - - - /** - * LOOKUP - * The LOOKUP function searches for value either from a one-row or one-column range or from an array. - * @param lookup_value The value that you want to match in lookup_array - * @param lookup_vector The range of cells being searched - * @param result_vector The column from which the matching value must be returned - * @return mixed The value of the found cell - */ - public static function LOOKUP($lookup_value, $lookup_vector, $result_vector=null) { - $lookup_value = self::flattenSingleValue($lookup_value); - - if (!is_array($lookup_vector)) { - return self::$_errorCodes['na']; - } - $lookupRows = count($lookup_vector); - $l = array_keys($lookup_vector); - $l = array_shift($l); - $lookupColumns = count($lookup_vector[$l]); - if ((($lookupRows == 1) && ($lookupColumns > 1)) || (($lookupRows == 2) && ($lookupColumns != 2))) { - $lookup_vector = self::TRANSPOSE($lookup_vector); - $lookupRows = count($lookup_vector); - $l = array_keys($lookup_vector); - $lookupColumns = count($lookup_vector[array_shift($l)]); - } - - if (is_null($result_vector)) { - $result_vector = $lookup_vector; - } - $resultRows = count($result_vector); - $l = array_keys($result_vector); - $l = array_shift($l); - $resultColumns = count($result_vector[$l]); - if ((($resultRows == 1) && ($resultColumns > 1)) || (($resultRows == 2) && ($resultColumns != 2))) { - $result_vector = self::TRANSPOSE($result_vector); - $resultRows = count($result_vector); - $r = array_keys($result_vector); - $resultColumns = count($result_vector[array_shift($r)]); - } - - if ($lookupRows == 2) { - $result_vector = array_pop($lookup_vector); - $lookup_vector = array_shift($lookup_vector); - } - if ($lookupColumns != 2) { - foreach($lookup_vector as &$value) { - if (is_array($value)) { - $k = array_keys($value); - $key1 = $key2 = array_shift($k); - $key2++; - $dataValue1 = $value[$key1]; - } else { - $key1 = 0; - $key2 = 1; - $dataValue1 = $value; - } - $dataValue2 = array_shift($result_vector); - if (is_array($dataValue2)) { - $dataValue2 = array_shift($dataValue2); - } - $value = array($key1 => $dataValue1, $key2 => $dataValue2); - } - unset($value); - } - - return self::VLOOKUP($lookup_value,$lookup_vector,2); - } // function LOOKUP() - - /** * Convert a multi-dimensional array to a simple 1-dimensional array * diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Logical.php b/libraries/PHPExcel/PHPExcel/Calculation/Logical.php new file mode 100644 index 000000000..427cc343a --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/Logical.php @@ -0,0 +1,290 @@ + '') { + if (strpos($sheetText,' ') !== False) { $sheetText = "'".$sheetText."'"; } + $sheetText .='!'; + } + if ((!is_bool($referenceStyle)) || $referenceStyle) { + $rowRelative = $columnRelative = '$'; + $column = PHPExcel_Cell::stringFromColumnIndex($column-1); + if (($relativity == 2) || ($relativity == 4)) { $columnRelative = ''; } + if (($relativity == 3) || ($relativity == 4)) { $rowRelative = ''; } + return $sheetText.$columnRelative.$column.$rowRelative.$row; + } else { + if (($relativity == 2) || ($relativity == 4)) { $column = '['.$column.']'; } + if (($relativity == 3) || ($relativity == 4)) { $row = '['.$row.']'; } + return $sheetText.'R'.$row.'C'.$column; + } + } // function CELL_ADDRESS() + + + /** + * COLUMN + * + * Returns the column number of the given cell reference + * If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array. + * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the + * reference of the cell in which the COLUMN function appears; otherwise this function returns 0. + * + * @param cellAddress A reference to a range of cells for which you want the column numbers + * @return integer or array of integer + */ + public static function COLUMN($cellAddress=Null) { + if (is_null($cellAddress) || trim($cellAddress) === '') { return 0; } + + if (is_array($cellAddress)) { + foreach($cellAddress as $columnKey => $value) { + $columnKey = preg_replace('/[^a-z]/i','',$columnKey); + return (integer) PHPExcel_Cell::columnIndexFromString($columnKey); + } + } else { + if (strpos($cellAddress,'!') !== false) { + list($sheet,$cellAddress) = explode('!',$cellAddress); + } + if (strpos($cellAddress,':') !== false) { + list($startAddress,$endAddress) = explode(':',$cellAddress); + $startAddress = preg_replace('/[^a-z]/i','',$startAddress); + $endAddress = preg_replace('/[^a-z]/i','',$endAddress); + $returnValue = array(); + do { + $returnValue[] = (integer) PHPExcel_Cell::columnIndexFromString($startAddress); + } while ($startAddress++ != $endAddress); + return $returnValue; + } else { + $cellAddress = preg_replace('/[^a-z]/i','',$cellAddress); + return (integer) PHPExcel_Cell::columnIndexFromString($cellAddress); + } + } + } // function COLUMN() + + + /** + * COLUMNS + * + * Returns the number of columns in an array or reference. + * + * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of columns + * @return integer + */ + public static function COLUMNS($cellAddress=Null) { + if (is_null($cellAddress) || $cellAddress === '') { + return 1; + } elseif (!is_array($cellAddress)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + $x = array_keys($cellAddress); + $x = array_shift($x); + $isMatrix = (is_numeric($x)); + list($columns,$rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress); + + if ($isMatrix) { + return $rows; + } else { + return $columns; + } + } // function COLUMNS() + + + /** + * ROW + * + * Returns the row number of the given cell reference + * If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array. + * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the + * reference of the cell in which the ROW function appears; otherwise this function returns 0. + * + * @param cellAddress A reference to a range of cells for which you want the row numbers + * @return integer or array of integer + */ + public static function ROW($cellAddress=Null) { + if (is_null($cellAddress) || trim($cellAddress) === '') { return 0; } + + if (is_array($cellAddress)) { + foreach($cellAddress as $columnKey => $rowValue) { + foreach($rowValue as $rowKey => $cellValue) { + return (integer) preg_replace('/[^0-9]/i','',$rowKey); + } + } + } else { + if (strpos($cellAddress,'!') !== false) { + list($sheet,$cellAddress) = explode('!',$cellAddress); + } + if (strpos($cellAddress,':') !== false) { + list($startAddress,$endAddress) = explode(':',$cellAddress); + $startAddress = preg_replace('/[^0-9]/','',$startAddress); + $endAddress = preg_replace('/[^0-9]/','',$endAddress); + $returnValue = array(); + do { + $returnValue[][] = (integer) $startAddress; + } while ($startAddress++ != $endAddress); + return $returnValue; + } else { + list($cellAddress) = explode(':',$cellAddress); + return (integer) preg_replace('/[^0-9]/','',$cellAddress); + } + } + } // function ROW() + + + /** + * ROWS + * + * Returns the number of rows in an array or reference. + * + * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows + * @return integer + */ + public static function ROWS($cellAddress=Null) { + if (is_null($cellAddress) || $cellAddress === '') { + return 1; + } elseif (!is_array($cellAddress)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + $i = array_keys($cellAddress); + $isMatrix = (is_numeric(array_shift($i))); + list($columns,$rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress); + + if ($isMatrix) { + return $columns; + } else { + return $rows; + } + } // function ROWS() + + + /** + * HYPERLINK + * + * Excel Function: + * =HYPERLINK(linkURL,displayName) + * + * @access public + * @category Logical Functions + * @param string $linkURL Value to check, is also the value returned when no error + * @param string $displayName Value to return when testValue is an error condition + * @return mixed The value of errorpart or testValue determined by error condition + */ + public static function HYPERLINK($linkURL = '', $displayName = null, PHPExcel_Cell $pCell = null) { + $args = func_get_args(); + $pCell = array_pop($args); + + $linkURL = (is_null($linkURL)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($linkURL); + $displayName = (is_null($displayName)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($displayName); + + if ((!is_object($pCell)) || (trim($linkURL) == '')) { + return PHPExcel_Calculation_Functions::REF(); + } + + if ((is_object($displayName)) || trim($displayName) == '') { + $displayName = $linkURL; + } + + $pCell->getHyperlink()->setUrl($linkURL); + + return $displayName; + } // function HYPERLINK() + + + /** + * INDIRECT + * + * Returns the number of rows in an array or reference. + * + * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows + * @return integer + */ + public static function INDIRECT($cellAddress=Null, PHPExcel_Cell $pCell = null) { + $cellAddress = PHPExcel_Calculation_Functions::flattenSingleValue($cellAddress); + if (is_null($cellAddress) || $cellAddress === '') { + return PHPExcel_Calculation_Functions::REF(); + } + + $cellAddress1 = $cellAddress; + $cellAddress2 = NULL; + if (strpos($cellAddress,':') !== false) { + list($cellAddress1,$cellAddress2) = explode(':',$cellAddress); + } + + if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress1, $matches)) || + ((!is_null($cellAddress2)) && (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress2, $matches)))) { + return PHPExcel_Calculation_Functions::REF(); + } + + if (strpos($cellAddress,'!') !== false) { + list($sheetName,$cellAddress) = explode('!',$cellAddress); + $pSheet = $pCell->getParent()->getParent()->getSheetByName($sheetName); + } else { + $pSheet = $pCell->getParent(); + } + + return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, False); + } // function INDIRECT() + + + /** + * OFFSET + * + * Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells. + * The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and + * the number of columns to be returned. + * + * @param cellAddress The reference from which you want to base the offset. Reference must refer to a cell or + * range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value. + * @param rows The number of rows, up or down, that you want the upper-left cell to refer to. + * Using 5 as the rows argument specifies that the upper-left cell in the reference is + * five rows below reference. Rows can be positive (which means below the starting reference) + * or negative (which means above the starting reference). + * @param cols The number of columns, to the left or right, that you want the upper-left cell of the result + * to refer to. Using 5 as the cols argument specifies that the upper-left cell in the + * reference is five columns to the right of reference. Cols can be positive (which means + * to the right of the starting reference) or negative (which means to the left of the + * starting reference). + * @param height The height, in number of rows, that you want the returned reference to be. Height must be a positive number. + * @param width The width, in number of columns, that you want the returned reference to be. Width must be a positive number. + * @return string A reference to a cell or range of cells + */ + public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null) { + $rows = PHPExcel_Calculation_Functions::flattenSingleValue($rows); + $columns = PHPExcel_Calculation_Functions::flattenSingleValue($columns); + $height = PHPExcel_Calculation_Functions::flattenSingleValue($height); + $width = PHPExcel_Calculation_Functions::flattenSingleValue($width); + if ($cellAddress == Null) { + return 0; + } + + $args = func_get_args(); + $pCell = array_pop($args); + if (!is_object($pCell)) { + return PHPExcel_Calculation_Functions::REF(); + } + + $sheetName = null; + if (strpos($cellAddress,"!")) { + list($sheetName,$cellAddress) = explode("!",$cellAddress); + } + if (strpos($cellAddress,":")) { + list($startCell,$endCell) = explode(":",$cellAddress); + } else { + $startCell = $endCell = $cellAddress; + } + list($startCellColumn,$startCellRow) = PHPExcel_Cell::coordinateFromString($startCell); + list($endCellColumn,$endCellRow) = PHPExcel_Cell::coordinateFromString($endCell); + + $startCellRow += $rows; + $startCellColumn = PHPExcel_Cell::columnIndexFromString($startCellColumn) - 1; + $startCellColumn += $columns; + + if (($startCellRow <= 0) || ($startCellColumn < 0)) { + return PHPExcel_Calculation_Functions::REF(); + } + $endCellColumn = PHPExcel_Cell::columnIndexFromString($endCellColumn) - 1; + if (($width != null) && (!is_object($width))) { + $endCellColumn = $startCellColumn + $width - 1; + } else { + $endCellColumn += $columns; + } + $startCellColumn = PHPExcel_Cell::stringFromColumnIndex($startCellColumn); + + if (($height != null) && (!is_object($height))) { + $endCellRow = $startCellRow + $height - 1; + } else { + $endCellRow += $rows; + } + + if (($endCellRow <= 0) || ($endCellColumn < 0)) { + return PHPExcel_Calculation_Functions::REF(); + } + $endCellColumn = PHPExcel_Cell::stringFromColumnIndex($endCellColumn); + + $cellAddress = $startCellColumn.$startCellRow; + if (($startCellColumn != $endCellColumn) || ($startCellRow != $endCellRow)) { + $cellAddress .= ':'.$endCellColumn.$endCellRow; + } + + if ($sheetName !== null) { + $pSheet = $pCell->getParent()->getParent()->getSheetByName($sheetName); + } else { + $pSheet = $pCell->getParent(); + } + + return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, False); + } // function OFFSET() + + + public static function CHOOSE() { + $chooseArgs = func_get_args(); + $chosenEntry = PHPExcel_Calculation_Functions::flattenArray(array_shift($chooseArgs)); + $entryCount = count($chooseArgs) - 1; + + if(is_array($chosenEntry)) { + $chosenEntry = array_shift($chosenEntry); + } + if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) { + --$chosenEntry; + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + $chosenEntry = floor($chosenEntry); + if (($chosenEntry <= 0) || ($chosenEntry > $entryCount)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (is_array($chooseArgs[$chosenEntry])) { + return PHPExcel_Calculation_Functions::flattenArray($chooseArgs[$chosenEntry]); + } else { + return $chooseArgs[$chosenEntry]; + } + } // function CHOOSE() + + + /** + * MATCH + * + * The MATCH function searches for a specified item in a range of cells + * + * @param lookup_value The value that you want to match in lookup_array + * @param lookup_array The range of cells being searched + * @param match_type The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered. + * @return integer The relative position of the found item + */ + public static function MATCH($lookup_value, $lookup_array, $match_type=1) { + $lookup_array = PHPExcel_Calculation_Functions::flattenArray($lookup_array); + $lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value); + $match_type = (is_null($match_type)) ? 1 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($match_type); + // MATCH is not case sensitive + $lookup_value = strtolower($lookup_value); + + // lookup_value type has to be number, text, or logical values + if ((!is_numeric($lookup_value)) && (!is_string($lookup_value)) && (!is_bool($lookup_value))) { + return PHPExcel_Calculation_Functions::NA(); + } + + // match_type is 0, 1 or -1 + if (($match_type !== 0) && ($match_type !== -1) && ($match_type !== 1)) { + return PHPExcel_Calculation_Functions::NA(); + } + + // lookup_array should not be empty + $lookupArraySize = count($lookup_array); + if ($lookupArraySize <= 0) { + return PHPExcel_Calculation_Functions::NA(); + } + + // lookup_array should contain only number, text, or logical values, or empty (null) cells + foreach($lookup_array as $i => $lookupArrayValue) { + // check the type of the value + if ((!is_numeric($lookupArrayValue)) && (!is_string($lookupArrayValue)) && + (!is_bool($lookupArrayValue)) && (!is_null($lookupArrayValue))) { + return PHPExcel_Calculation_Functions::NA(); + } + // convert strings to lowercase for case-insensitive testing + if (is_string($lookupArrayValue)) { + $lookup_array[$i] = strtolower($lookupArrayValue); + } + if ((is_null($lookupArrayValue)) && (($match_type == 1) || ($match_type == -1))) { + $lookup_array = array_slice($lookup_array,0,$i-1); + } + } + + // if match_type is 1 or -1, the list has to be ordered + if ($match_type == 1) { + asort($lookup_array); + $keySet = array_keys($lookup_array); + } elseif($match_type == -1) { + arsort($lookup_array); + $keySet = array_keys($lookup_array); + } + + // ** + // find the match + // ** + // loop on the cells +// var_dump($lookup_array); +// echo '
'; + foreach($lookup_array as $i => $lookupArrayValue) { + if (($match_type == 0) && ($lookupArrayValue == $lookup_value)) { + // exact match + return ++$i; + } elseif (($match_type == -1) && ($lookupArrayValue <= $lookup_value)) { +// echo '$i = '.$i.' => '; +// var_dump($lookupArrayValue); +// echo '
'; +// echo 'Keyset = '; +// var_dump($keySet); +// echo '
'; + $i = array_search($i,$keySet); +// echo '$i='.$i.'
'; + // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value + if ($i < 1){ + // 1st cell was allready smaller than the lookup_value + break; + } else { + // the previous cell was the match + return $keySet[$i-1]+1; + } + } elseif (($match_type == 1) && ($lookupArrayValue >= $lookup_value)) { +// echo '$i = '.$i.' => '; +// var_dump($lookupArrayValue); +// echo '
'; +// echo 'Keyset = '; +// var_dump($keySet); +// echo '
'; + $i = array_search($i,$keySet); +// echo '$i='.$i.'
'; + // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value + if ($i < 1){ + // 1st cell was allready bigger than the lookup_value + break; + } else { + // the previous cell was the match + return $keySet[$i-1]+1; + } + } + } + + // unsuccessful in finding a match, return #N/A error value + return PHPExcel_Calculation_Functions::NA(); + } // function MATCH() + + + /** + * INDEX + * + * Uses an index to choose a value from a reference or array + * implemented: Return the value of a specified cell or array of cells Array form + * not implemented: Return a reference to specified cells Reference form + * + * @param range_array a range of cells or an array constant + * @param row_num selects the row in array from which to return a value. If row_num is omitted, column_num is required. + * @param column_num selects the column in array from which to return a value. If column_num is omitted, row_num is required. + */ + public static function INDEX($arrayValues,$rowNum = 0,$columnNum = 0) { + + if (($rowNum < 0) || ($columnNum < 0)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (!is_array($arrayValues)) { + return PHPExcel_Calculation_Functions::REF(); + } + + $rowKeys = array_keys($arrayValues); + $columnKeys = @array_keys($arrayValues[$rowKeys[0]]); + + if ($columnNum > count($columnKeys)) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ($columnNum == 0) { + if ($rowNum == 0) { + return $arrayValues; + } + $rowNum = $rowKeys[--$rowNum]; + $returnArray = array(); + foreach($arrayValues as $arrayColumn) { + if (is_array($arrayColumn)) { + if (isset($arrayColumn[$rowNum])) { + $returnArray[] = $arrayColumn[$rowNum]; + } else { + return $arrayValues[$rowNum]; + } + } else { + return $arrayValues[$rowNum]; + } + } + return $returnArray; + } + $columnNum = $columnKeys[--$columnNum]; + if ($rowNum > count($rowKeys)) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ($rowNum == 0) { + return $arrayValues[$columnNum]; + } + $rowNum = $rowKeys[--$rowNum]; + + return $arrayValues[$rowNum][$columnNum]; + } // function INDEX() + + + /** + * TRANSPOSE + * + * @param array $matrixData A matrix of values + * @return array + * + * Unlike the Excel TRANSPOSE function, which will only work on a single row or column, this function will transpose a full matrix. + */ + public static function TRANSPOSE($matrixData) { + $returnMatrix = array(); + if (!is_array($matrixData)) { $matrixData = array(array($matrixData)); } + + $column = 0; + foreach($matrixData as $matrixRow) { + $row = 0; + foreach($matrixRow as $matrixCell) { + $returnMatrix[$row][$column] = $matrixCell; + ++$row; + } + ++$column; + } + return $returnMatrix; + } // function TRANSPOSE() + + + private static function _vlookupSort($a,$b) { + $f = array_keys($a); + $firstColumn = array_shift($f); + if (strtolower($a[$firstColumn]) == strtolower($b[$firstColumn])) { + return 0; + } + return (strtolower($a[$firstColumn]) < strtolower($b[$firstColumn])) ? -1 : 1; + } // function _vlookupSort() + + + /** + * VLOOKUP + * The VLOOKUP function searches for value in the left-most column of lookup_array and returns the value in the same row based on the index_number. + * @param lookup_value The value that you want to match in lookup_array + * @param lookup_array The range of cells being searched + * @param index_number The column number in table_array from which the matching value must be returned. The first column is 1. + * @param not_exact_match Determines if you are looking for an exact match based on lookup_value. + * @return mixed The value of the found cell + */ + public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match=true) { + $lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value); + $index_number = PHPExcel_Calculation_Functions::flattenSingleValue($index_number); + $not_exact_match = PHPExcel_Calculation_Functions::flattenSingleValue($not_exact_match); + + // index_number must be greater than or equal to 1 + if ($index_number < 1) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // index_number must be less than or equal to the number of columns in lookup_array + if ((!is_array($lookup_array)) || (count($lookup_array) < 1)) { + return PHPExcel_Calculation_Functions::REF(); + } else { + $f = array_keys($lookup_array); + $firstRow = array_pop($f); + if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array[$firstRow]))) { + return PHPExcel_Calculation_Functions::REF(); + } else { + $columnKeys = array_keys($lookup_array[$firstRow]); + $returnColumn = $columnKeys[--$index_number]; + $firstColumn = array_shift($columnKeys); + } + } + + if (!$not_exact_match) { + uasort($lookup_array,array('self','_vlookupSort')); + } + + $rowNumber = $rowValue = False; + foreach($lookup_array as $rowKey => $rowData) { + if (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)) { + break; + } + $rowNumber = $rowKey; + $rowValue = $rowData[$firstColumn]; + } + + if ($rowNumber !== false) { + if ((!$not_exact_match) && ($rowValue != $lookup_value)) { + // if an exact match is required, we have what we need to return an appropriate response + return PHPExcel_Calculation_Functions::NA(); + } else { + // otherwise return the appropriate value + return $lookup_array[$rowNumber][$returnColumn]; + } + } + + return PHPExcel_Calculation_Functions::NA(); + } // function VLOOKUP() + + + /** + * LOOKUP + * The LOOKUP function searches for value either from a one-row or one-column range or from an array. + * @param lookup_value The value that you want to match in lookup_array + * @param lookup_vector The range of cells being searched + * @param result_vector The column from which the matching value must be returned + * @return mixed The value of the found cell + */ + public static function LOOKUP($lookup_value, $lookup_vector, $result_vector=null) { + $lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value); + + if (!is_array($lookup_vector)) { + return PHPExcel_Calculation_Functions::NA(); + } + $lookupRows = count($lookup_vector); + $l = array_keys($lookup_vector); + $l = array_shift($l); + $lookupColumns = count($lookup_vector[$l]); + if ((($lookupRows == 1) && ($lookupColumns > 1)) || (($lookupRows == 2) && ($lookupColumns != 2))) { + $lookup_vector = self::TRANSPOSE($lookup_vector); + $lookupRows = count($lookup_vector); + $l = array_keys($lookup_vector); + $lookupColumns = count($lookup_vector[array_shift($l)]); + } + + if (is_null($result_vector)) { + $result_vector = $lookup_vector; + } + $resultRows = count($result_vector); + $l = array_keys($result_vector); + $l = array_shift($l); + $resultColumns = count($result_vector[$l]); + if ((($resultRows == 1) && ($resultColumns > 1)) || (($resultRows == 2) && ($resultColumns != 2))) { + $result_vector = self::TRANSPOSE($result_vector); + $resultRows = count($result_vector); + $r = array_keys($result_vector); + $resultColumns = count($result_vector[array_shift($r)]); + } + + if ($lookupRows == 2) { + $result_vector = array_pop($lookup_vector); + $lookup_vector = array_shift($lookup_vector); + } + if ($lookupColumns != 2) { + foreach($lookup_vector as &$value) { + if (is_array($value)) { + $k = array_keys($value); + $key1 = $key2 = array_shift($k); + $key2++; + $dataValue1 = $value[$key1]; + } else { + $key1 = 0; + $key2 = 1; + $dataValue1 = $value; + } + $dataValue2 = array_shift($result_vector); + if (is_array($dataValue2)) { + $dataValue2 = array_shift($dataValue2); + } + $value = array($key1 => $dataValue1, $key2 => $dataValue2); + } + unset($value); + } + + return self::VLOOKUP($lookup_value,$lookup_vector,2); + } // function LOOKUP() + +} // class PHPExcel_Calculation_LookupRef diff --git a/libraries/PHPExcel/PHPExcel/Calculation/MathTrig.php b/libraries/PHPExcel/PHPExcel/Calculation/MathTrig.php new file mode 100644 index 000000000..35530274d --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/MathTrig.php @@ -0,0 +1,1241 @@ + 1; --$i) { + if (($value % $i) == 0) { + $factorArray = array_merge($factorArray,self::_factors($value / $i)); + $factorArray = array_merge($factorArray,self::_factors($i)); + if ($i <= sqrt($value)) { + break; + } + } + } + if (count($factorArray) > 0) { + rsort($factorArray); + return $factorArray; + } else { + return array((integer) $value); + } + } // function _factors() + + + private static function _romanCut($num, $n) { + return ($num - ($num % $n ) ) / $n; + } // function _romanCut() + + + /** + * ATAN2 + * + * This function calculates the arc tangent of the two variables x and y. It is similar to + * calculating the arc tangent of y ÷ x, except that the signs of both arguments are used + * to determine the quadrant of the result. + * The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a + * point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between + * -pi and pi, excluding -pi. + * + * Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard + * PHP atan2() function, so we need to reverse them here before calling the PHP atan() function. + * + * Excel Function: + * ATAN2(xCoordinate,yCoordinate) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param float $xCoordinate The x-coordinate of the point. + * @param float $yCoordinate The y-coordinate of the point. + * @return float The inverse tangent of the specified x- and y-coordinates. + */ + public static function ATAN2($xCoordinate, $yCoordinate) { + $xCoordinate = (float) PHPExcel_Calculation_Functions::flattenSingleValue($xCoordinate); + $yCoordinate = (float) PHPExcel_Calculation_Functions::flattenSingleValue($yCoordinate); + + if (($xCoordinate == 0) && ($yCoordinate == 0)) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + return atan2($yCoordinate, $xCoordinate); + } // function REVERSE_ATAN2() + + + /** + * CEILING + * + * Returns number rounded up, away from zero, to the nearest multiple of significance. + * + * @param float $number Number to round + * @param float $significance Significance + * @return float Rounded Number + */ + public static function CEILING($number,$significance=null) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + $significance = PHPExcel_Calculation_Functions::flattenSingleValue($significance); + + if ((is_null($significance)) && (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) { + $significance = $number/abs($number); + } + + if ((is_numeric($number)) && (is_numeric($significance))) { + if (self::SIGN($number) == self::SIGN($significance)) { + if ($significance == 0.0) { + return 0; + } + return ceil($number / $significance) * $significance; + } else { + return PHPExcel_Calculation_Functions::NaN(); + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function CEILING() + + + /** + * COMBIN + * + * Returns the number of combinations for a given number of items. Use COMBIN to + * determine the total possible number of groups for a given number of items. + * + * @param int $numObjs Number of different objects + * @param int $numInSet Number of objects in each combination + * @return int Number of combinations + */ + public static function COMBIN($numObjs,$numInSet) { + $numObjs = PHPExcel_Calculation_Functions::flattenSingleValue($numObjs); + $numInSet = PHPExcel_Calculation_Functions::flattenSingleValue($numInSet); + + if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { + if ($numObjs < $numInSet) { + return PHPExcel_Calculation_Functions::NaN(); + } elseif ($numInSet < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function COMBIN() + + + /** + * EVEN + * + * Returns number rounded up to the nearest even integer. + * + * @param float $number Number to round + * @return int Rounded Number + */ + public static function EVEN($number) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + + if (is_null($number)) { + return 0; + } elseif (is_numeric($number)) { + $significance = 2 * self::SIGN($number); + return (int) self::CEILING($number,$significance); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function EVEN() + + + /** + * FACT + * + * Returns the factorial of a number. + * + * @param float $factVal Factorial Value + * @return int Factorial + */ + public static function FACT($factVal) { + $factVal = PHPExcel_Calculation_Functions::flattenSingleValue($factVal); + + if (is_numeric($factVal)) { + if ($factVal < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $factLoop = floor($factVal); + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + if ($factVal > $factLoop) { + return PHPExcel_Calculation_Functions::NaN(); + } + } + + $factorial = 1; + while ($factLoop > 1) { + $factorial *= $factLoop--; + } + return $factorial ; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function FACT() + + + /** + * FACTDOUBLE + * + * Returns the double factorial of a number. + * + * @param float $factVal Factorial Value + * @return int Double Factorial + */ + public static function FACTDOUBLE($factVal) { + $factLoop = floor(PHPExcel_Calculation_Functions::flattenSingleValue($factVal)); + + if (is_numeric($factLoop)) { + if ($factVal < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $factorial = 1; + while ($factLoop > 1) { + $factorial *= $factLoop--; + --$factLoop; + } + return $factorial ; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function FACTDOUBLE() + + + /** + * FLOOR + * + * Rounds number down, toward zero, to the nearest multiple of significance. + * + * @param float $number Number to round + * @param float $significance Significance + * @return float Rounded Number + */ + public static function FLOOR($number,$significance=null) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + $significance = PHPExcel_Calculation_Functions::flattenSingleValue($significance); + + if ((is_null($significance)) && (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) { + $significance = $number/abs($number); + } + + if ((is_numeric($number)) && (is_numeric($significance))) { + if ((float) $significance == 0.0) { + return PHPExcel_Calculation_Functions::DIV0(); + } + if (self::SIGN($number) == self::SIGN($significance)) { + return floor($number / $significance) * $significance; + } else { + return PHPExcel_Calculation_Functions::NaN(); + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function FLOOR() + + + /** + * GCD + * + * Returns the greatest common divisor of a series of numbers + * + * @param $array Values to calculate the Greatest Common Divisor + * @return int Greatest Common Divisor + */ + public static function GCD() { + $returnValue = 1; + $allPoweredFactors = array(); + // Loop through arguments + foreach(PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $value) { + if ($value == 0) { + break; + } + $myFactors = self::_factors($value); + $myCountedFactors = array_count_values($myFactors); + $allValuesFactors[] = $myCountedFactors; + } + $allValuesCount = count($allValuesFactors); + $mergedArray = $allValuesFactors[0]; + for ($i=1;$i < $allValuesCount; ++$i) { + $mergedArray = array_intersect_key($mergedArray,$allValuesFactors[$i]); + } + $mergedArrayValues = count($mergedArray); + if ($mergedArrayValues == 0) { + return $returnValue; + } elseif ($mergedArrayValues > 1) { + foreach($mergedArray as $mergedKey => $mergedValue) { + foreach($allValuesFactors as $highestPowerTest) { + foreach($highestPowerTest as $testKey => $testValue) { + if (($testKey == $mergedKey) && ($testValue < $mergedValue)) { + $mergedArray[$mergedKey] = $testValue; + $mergedValue = $testValue; + } + } + } + } + + $returnValue = 1; + foreach($mergedArray as $key => $value) { + $returnValue *= pow($key,$value); + } + return $returnValue; + } else { + $keys = array_keys($mergedArray); + $key = $keys[0]; + $value = $mergedArray[$key]; + foreach($allValuesFactors as $testValue) { + foreach($testValue as $mergedKey => $mergedValue) { + if (($mergedKey == $key) && ($mergedValue < $value)) { + $value = $mergedValue; + } + } + } + return pow($key,$value); + } + } // function GCD() + + + /** + * INT + * + * Casts a floating point value to an integer + * + * @param float $number Number to cast to an integer + * @return integer Integer value + */ + public static function INT($number) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + + if (is_numeric($number)) { + return (int) floor($number); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function INT() + + + /** + * LCM + * + * Returns the lowest common multiplier of a series of numbers + * + * @param $array Values to calculate the Lowest Common Multiplier + * @return int Lowest Common Multiplier + */ + public static function LCM() { + $returnValue = 1; + $allPoweredFactors = array(); + // Loop through arguments + foreach(PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $value) { + if (!is_numeric($value)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if ($value == 0) { + return 0; + } elseif ($value < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $myFactors = self::_factors(floor($value)); + $myCountedFactors = array_count_values($myFactors); + $myPoweredFactors = array(); + foreach($myCountedFactors as $myCountedFactor => $myCountedPower) { + $myPoweredFactors[$myCountedFactor] = pow($myCountedFactor,$myCountedPower); + } + foreach($myPoweredFactors as $myPoweredValue => $myPoweredFactor) { + if (array_key_exists($myPoweredValue,$allPoweredFactors)) { + if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) { + $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; + } + } else { + $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; + } + } + } + foreach($allPoweredFactors as $allPoweredFactor) { + $returnValue *= (integer) $allPoweredFactor; + } + return $returnValue; + } // function LCM() + + + /** + * LOG_BASE + * + * Returns the logarithm of a number to a specified base. The default base is 10. + * + * Excel Function: + * LOG(number[,base]) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param float $value The positive real number for which you want the logarithm + * @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10. + * @return float + */ + public static function LOG_BASE($number, $base=10) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + $base = (is_null($base)) ? 10 : (float) PHPExcel_Calculation_Functions::flattenSingleValue($base); + + return log($number, $base); + } // function LOG_BASE() + + + /** + * MDETERM + * + * @param array $matrixValues A matrix of values + * @return float + */ + public static function MDETERM($matrixValues) { + $matrixData = array(); + if (!is_array($matrixValues)) { $matrixValues = array(array($matrixValues)); } + + $row = $maxColumn = 0; + foreach($matrixValues as $matrixRow) { + $column = 0; + foreach($matrixRow as $matrixCell) { + if ((is_string($matrixCell)) || ($matrixCell === null)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $matrixData[$column][$row] = $matrixCell; + ++$column; + } + if ($column > $maxColumn) { $maxColumn = $column; } + ++$row; + } + if ($row != $maxColumn) { return PHPExcel_Calculation_Functions::VALUE(); } + + try { + $matrix = new PHPExcel_Shared_JAMA_Matrix($matrixData); + return $matrix->det(); + } catch (Exception $ex) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } // function MDETERM() + + + /** + * MINVERSE + * + * @param array $matrixValues A matrix of values + * @return array + */ + public static function MINVERSE($matrixValues) { + $matrixData = array(); + if (!is_array($matrixValues)) { $matrixValues = array(array($matrixValues)); } + + $row = $maxColumn = 0; + foreach($matrixValues as $matrixRow) { + $column = 0; + foreach($matrixRow as $matrixCell) { + if ((is_string($matrixCell)) || ($matrixCell === null)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $matrixData[$column][$row] = $matrixCell; + ++$column; + } + if ($column > $maxColumn) { $maxColumn = $column; } + ++$row; + } + if ($row != $maxColumn) { return PHPExcel_Calculation_Functions::VALUE(); } + + try { + $matrix = new PHPExcel_Shared_JAMA_Matrix($matrixData); + return $matrix->inverse()->getArray(); + } catch (Exception $ex) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } // function MINVERSE() + + + /** + * MMULT + * + * @param array $matrixData1 A matrix of values + * @param array $matrixData2 A matrix of values + * @return array + */ + public static function MMULT($matrixData1,$matrixData2) { + $matrixAData = $matrixBData = array(); + if (!is_array($matrixData1)) { $matrixData1 = array(array($matrixData1)); } + if (!is_array($matrixData2)) { $matrixData2 = array(array($matrixData2)); } + + $rowA = 0; + foreach($matrixData1 as $matrixRow) { + $columnA = 0; + foreach($matrixRow as $matrixCell) { + if ((is_string($matrixCell)) || ($matrixCell === null)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $matrixAData[$rowA][$columnA] = $matrixCell; + ++$columnA; + } + ++$rowA; + } + try { + $matrixA = new PHPExcel_Shared_JAMA_Matrix($matrixAData); + $rowB = 0; + foreach($matrixData2 as $matrixRow) { + $columnB = 0; + foreach($matrixRow as $matrixCell) { + if ((is_string($matrixCell)) || ($matrixCell === null)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $matrixBData[$rowB][$columnB] = $matrixCell; + ++$columnB; + } + ++$rowB; + } + $matrixB = new PHPExcel_Shared_JAMA_Matrix($matrixBData); + + if (($rowA != $columnB) || ($rowB != $columnA)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + return $matrixA->times($matrixB)->getArray(); + } catch (Exception $ex) { + return PHPExcel_Calculation_Functions::VALUE(); + } + } // function MMULT() + + + /** + * MOD + * + * @param int $a Dividend + * @param int $b Divisor + * @return int Remainder + */ + public static function MOD($a = 1, $b = 1) { + $a = PHPExcel_Calculation_Functions::flattenSingleValue($a); + $b = PHPExcel_Calculation_Functions::flattenSingleValue($b); + + if ($b == 0.0) { + return PHPExcel_Calculation_Functions::DIV0(); + } elseif (($a < 0.0) && ($b > 0.0)) { + return $b - fmod(abs($a),$b); + } elseif (($a > 0.0) && ($b < 0.0)) { + return $b + fmod($a,abs($b)); + } + + return fmod($a,$b); + } // function MOD() + + + /** + * MROUND + * + * Rounds a number to the nearest multiple of a specified value + * + * @param float $number Number to round + * @param int $multiple Multiple to which you want to round $number + * @return float Rounded Number + */ + public static function MROUND($number,$multiple) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + $multiple = PHPExcel_Calculation_Functions::flattenSingleValue($multiple); + + if ((is_numeric($number)) && (is_numeric($multiple))) { + if ($multiple == 0) { + return 0; + } + if ((self::SIGN($number)) == (self::SIGN($multiple))) { + $multiplier = 1 / $multiple; + return round($number * $multiplier) / $multiplier; + } + return PHPExcel_Calculation_Functions::NaN(); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function MROUND() + + + /** + * MULTINOMIAL + * + * Returns the ratio of the factorial of a sum of values to the product of factorials. + * + * @param array of mixed Data Series + * @return float + */ + public static function MULTINOMIAL() { + $summer = 0; + $divisor = 1; + // Loop through arguments + foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) { + // Is it a numeric value? + if (is_numeric($arg)) { + if ($arg < 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + $summer += floor($arg); + $divisor *= self::FACT($arg); + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + + // Return + if ($summer > 0) { + $summer = self::FACT($summer); + return $summer / $divisor; + } + return 0; + } // function MULTINOMIAL() + + + /** + * ODD + * + * Returns number rounded up to the nearest odd integer. + * + * @param float $number Number to round + * @return int Rounded Number + */ + public static function ODD($number) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + + if (is_null($number)) { + return 1; + } elseif (is_numeric($number)) { + $significance = self::SIGN($number); + if ($significance == 0) { + return 1; + } + + $result = self::CEILING($number,$significance); + if ($result == self::EVEN($result)) { + $result += $significance; + } + + return (int) $result; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function ODD() + + + /** + * POWER + * + * Computes x raised to the power y. + * + * @param float $x + * @param float $y + * @return float + */ + public static function POWER($x = 0, $y = 2) { + $x = PHPExcel_Calculation_Functions::flattenSingleValue($x); + $y = PHPExcel_Calculation_Functions::flattenSingleValue($y); + + // Validate parameters + if ($x == 0 && $y <= 0) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + // Return + return pow($x, $y); + } // function POWER() + + + /** + * PRODUCT + * + * PRODUCT returns the product of all the values and cells referenced in the argument list. + * + * Excel Function: + * PRODUCT(value1[,value2[, ...]]) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function PRODUCT() { + // Return value + $returnValue = null; + + // Loop through arguments + foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if (is_null($returnValue)) { + $returnValue = $arg; + } else { + $returnValue *= $arg; + } + } + } + + // Return + if (is_null($returnValue)) { + return 0; + } + return $returnValue; + } // function PRODUCT() + + + /** + * QUOTIENT + * + * QUOTIENT function returns the integer portion of a division. Numerator is the divided number + * and denominator is the divisor. + * + * Excel Function: + * QUOTIENT(value1[,value2[, ...]]) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function QUOTIENT() { + // Return value + $returnValue = null; + + // Loop through arguments + foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if (is_null($returnValue)) { + $returnValue = ($arg == 0) ? 0 : $arg; + } else { + if (($returnValue == 0) || ($arg == 0)) { + $returnValue = 0; + } else { + $returnValue /= $arg; + } + } + } + } + + // Return + return intval($returnValue); + } // function QUOTIENT() + + + /** + * RAND + * + * @param int $min Minimal value + * @param int $max Maximal value + * @return int Random number + */ + public static function RAND($min = 0, $max = 0) { + $min = PHPExcel_Calculation_Functions::flattenSingleValue($min); + $max = PHPExcel_Calculation_Functions::flattenSingleValue($max); + + if ($min == 0 && $max == 0) { + return (rand(0,10000000)) / 10000000; + } else { + return rand($min, $max); + } + } // function RAND() + + + public static function ROMAN($aValue, $style=0) { + $aValue = (integer) PHPExcel_Calculation_Functions::flattenSingleValue($aValue); + $style = (is_null($style)) ? 0 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($style); + if ((!is_numeric($aValue)) || ($aValue < 0) || ($aValue >= 4000)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if ($aValue == 0) { + return ''; + } + + $mill = Array('', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM'); + $cent = Array('', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'); + $tens = Array('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'); + $ones = Array('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'); + + $roman = ''; + while ($aValue > 5999) { + $roman .= 'M'; + $aValue -= 1000; + } + $m = self::_romanCut($aValue, 1000); $aValue %= 1000; + $c = self::_romanCut($aValue, 100); $aValue %= 100; + $t = self::_romanCut($aValue, 10); $aValue %= 10; + + return $roman.$mill[$m].$cent[$c].$tens[$t].$ones[$aValue]; + } // function ROMAN() + + + /** + * ROUNDUP + * + * Rounds a number up to a specified number of decimal places + * + * @param float $number Number to round + * @param int $digits Number of digits to which you want to round $number + * @return float Rounded Number + */ + public static function ROUNDUP($number,$digits) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + $digits = PHPExcel_Calculation_Functions::flattenSingleValue($digits); + + if ((is_numeric($number)) && (is_numeric($digits))) { + $significance = pow(10,$digits); + if ($number < 0.0) { + return floor($number * $significance) / $significance; + } else { + return ceil($number * $significance) / $significance; + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function ROUNDUP() + + + /** + * ROUNDDOWN + * + * Rounds a number down to a specified number of decimal places + * + * @param float $number Number to round + * @param int $digits Number of digits to which you want to round $number + * @return float Rounded Number + */ + public static function ROUNDDOWN($number,$digits) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + $digits = PHPExcel_Calculation_Functions::flattenSingleValue($digits); + + if ((is_numeric($number)) && (is_numeric($digits))) { + $significance = pow(10,$digits); + if ($number < 0.0) { + return ceil($number * $significance) / $significance; + } else { + return floor($number * $significance) / $significance; + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function ROUNDDOWN() + + + /** + * SERIESSUM + * + * Returns the sum of a power series + * + * @param float $x Input value to the power series + * @param float $n Initial power to which you want to raise $x + * @param float $m Step by which to increase $n for each term in the series + * @param array of mixed Data Series + * @return float + */ + public static function SERIESSUM() { + // Return value + $returnValue = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + $x = array_shift($aArgs); + $n = array_shift($aArgs); + $m = array_shift($aArgs); + + if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) { + // Calculate + $i = 0; + foreach($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $returnValue += $arg * pow($x,$n + ($m * $i++)); + } else { + return PHPExcel_Calculation_Functions::VALUE(); + } + } + // Return + return $returnValue; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SERIESSUM() + + + /** + * SIGN + * + * Determines the sign of a number. Returns 1 if the number is positive, zero (0) + * if the number is 0, and -1 if the number is negative. + * + * @param float $number Number to round + * @return int sign value + */ + public static function SIGN($number) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + + if (is_numeric($number)) { + if ($number == 0.0) { + return 0; + } + return $number / abs($number); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SIGN() + + + /** + * SQRTPI + * + * Returns the square root of (number * pi). + * + * @param float $number Number + * @return float Square Root of Number * Pi + */ + public static function SQRTPI($number) { + $number = PHPExcel_Calculation_Functions::flattenSingleValue($number); + + if (is_numeric($number)) { + if ($number < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return sqrt($number * M_PI) ; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SQRTPI() + + + /** + * SUBTOTAL + * + * Returns a subtotal in a list or database. + * + * @param int the number 1 to 11 that specifies which function to + * use in calculating subtotals within a list. + * @param array of mixed Data Series + * @return float + */ + public static function SUBTOTAL() { + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + // Calculate + $subtotal = array_shift($aArgs); + + if ((is_numeric($subtotal)) && (!is_string($subtotal))) { + switch($subtotal) { + case 1 : + return PHPExcel_Calculation_Statistical::AVERAGE($aArgs); + break; + case 2 : + return PHPExcel_Calculation_Statistical::COUNT($aArgs); + break; + case 3 : + return PHPExcel_Calculation_Statistical::COUNTA($aArgs); + break; + case 4 : + return PHPExcel_Calculation_Statistical::MAX($aArgs); + break; + case 5 : + return PHPExcel_Calculation_Statistical::MIN($aArgs); + break; + case 6 : + return self::PRODUCT($aArgs); + break; + case 7 : + return PHPExcel_Calculation_Statistical::STDEV($aArgs); + break; + case 8 : + return PHPExcel_Calculation_Statistical::STDEVP($aArgs); + break; + case 9 : + return self::SUM($aArgs); + break; + case 10 : + return PHPExcel_Calculation_Statistical::VARFunc($aArgs); + break; + case 11 : + return PHPExcel_Calculation_Statistical::VARP($aArgs); + break; + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SUBTOTAL() + + + /** + * SUM + * + * SUM computes the sum of all the values and cells referenced in the argument list. + * + * Excel Function: + * SUM(value1[,value2[, ...]]) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function SUM() { + // Return value + $returnValue = 0; + + // Loop through the arguments + foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $returnValue += $arg; + } + } + + // Return + return $returnValue; + } // function SUM() + + + /** + * SUMIF + * + * Counts the number of cells that contain numbers within the list of arguments + * + * Excel Function: + * SUMIF(value1[,value2[, ...]],condition) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @param string $condition The criteria that defines which cells will be summed. + * @return float + */ + public static function SUMIF($aArgs,$condition,$sumArgs = array()) { + // Return value + $returnValue = 0; + + $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs); + $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs); + if (count($sumArgs) == 0) { + $sumArgs = $aArgs; + } + $condition = PHPExcel_Calculation_Functions::_ifCondition($condition); + // Loop through arguments + foreach ($aArgs as $key => $arg) { + if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } + $testCondition = '='.$arg.$condition; + if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { + // Is it a value within our criteria + $returnValue += $sumArgs[$key]; + } + } + + // Return + return $returnValue; + } // function SUMIF() + + + /** + * SUMPRODUCT + * + * @param mixed $value Value to check + * @return float + */ + public static function SUMPRODUCT() { + $arrayList = func_get_args(); + + $wrkArray = PHPExcel_Calculation_Functions::flattenArray(array_shift($arrayList)); + $wrkCellCount = count($wrkArray); + + foreach($arrayList as $matrixData) { + $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData); + $count = count($array2); + if ($wrkCellCount != $count) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + foreach ($array2 as $i => $val) { + if (((is_numeric($wrkArray[$i])) && (!is_string($wrkArray[$i]))) && + ((is_numeric($val)) && (!is_string($val)))) { + $wrkArray[$i] *= $val; + } + } + } + + return array_sum($wrkArray); + } // function SUMPRODUCT() + + + /** + * SUMSQ + * + * SUMSQ returns the sum of the squares of the arguments + * + * Excel Function: + * SUMSQ(value1[,value2[, ...]]) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function SUMSQ() { + // Return value + $returnValue = 0; + + // Loop through arguments + foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $returnValue += ($arg * $arg); + } + } + + // Return + return $returnValue; + } // function SUMSQ() + + + /** + * SUMX2MY2 + * + * @param mixed $value Value to check + * @return float + */ + public static function SUMX2MY2($matrixData1,$matrixData2) { + $array1 = PHPExcel_Calculation_Functions::flattenArray($matrixData1); + $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData2); + $count1 = count($array1); + $count2 = count($array2); + if ($count1 < $count2) { + $count = $count1; + } else { + $count = $count2; + } + + $result = 0; + for ($i = 0; $i < $count; ++$i) { + if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && + ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) { + $result += ($array1[$i] * $array1[$i]) - ($array2[$i] * $array2[$i]); + } + } + + return $result; + } // function SUMX2MY2() + + + /** + * SUMX2PY2 + * + * @param mixed $value Value to check + * @return float + */ + public static function SUMX2PY2($matrixData1,$matrixData2) { + $array1 = PHPExcel_Calculation_Functions::flattenArray($matrixData1); + $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData2); + $count1 = count($array1); + $count2 = count($array2); + if ($count1 < $count2) { + $count = $count1; + } else { + $count = $count2; + } + + $result = 0; + for ($i = 0; $i < $count; ++$i) { + if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && + ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) { + $result += ($array1[$i] * $array1[$i]) + ($array2[$i] * $array2[$i]); + } + } + + return $result; + } // function SUMX2PY2() + + + /** + * SUMXMY2 + * + * @param mixed $value Value to check + * @return float + */ + public static function SUMXMY2($matrixData1,$matrixData2) { + $array1 = PHPExcel_Calculation_Functions::flattenArray($matrixData1); + $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData2); + $count1 = count($array1); + $count2 = count($array2); + if ($count1 < $count2) { + $count = $count1; + } else { + $count = $count2; + } + + $result = 0; + for ($i = 0; $i < $count; ++$i) { + if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && + ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) { + $result += ($array1[$i] - $array2[$i]) * ($array1[$i] - $array2[$i]); + } + } + + return $result; + } // function SUMXMY2() + + + /** + * TRUNC + * + * Truncates value to the number of fractional digits by number_digits. + * + * @param float $value + * @param int $number_digits + * @return float Truncated value + */ + public static function TRUNC($value = 0, $number_digits = 0) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $number_digits = PHPExcel_Calculation_Functions::flattenSingleValue($number_digits); + + // Validate parameters + if ($number_digits < 0) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + // Truncate + if ($number_digits > 0) { + $value = $value * pow(10, $number_digits); + } + $value = intval($value); + if ($number_digits > 0) { + $value = $value / pow(10, $number_digits); + } + + // Return + return $value; + } // function TRUNC() + +} // class PHPExcel_Calculation_MathTrig diff --git a/libraries/PHPExcel/PHPExcel/Calculation/Statistical.php b/libraries/PHPExcel/PHPExcel/Calculation/Statistical.php new file mode 100644 index 000000000..31c92964a --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/Statistical.php @@ -0,0 +1,3643 @@ + $value) { + if ((is_bool($value)) || (is_string($value)) || (is_null($value))) { + unset($array1[$key]); + unset($array2[$key]); + } + } + foreach($array2 as $key => $value) { + if ((is_bool($value)) || (is_string($value)) || (is_null($value))) { + unset($array1[$key]); + unset($array2[$key]); + } + } + $array1 = array_merge($array1); + $array2 = array_merge($array2); + + return True; + } // function _checkTrendArrays() + + + /** + * Beta function. + * + * @author Jaco van Kooten + * + * @param p require p>0 + * @param q require q>0 + * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow + */ + private static function _beta($p, $q) { + if ($p <= 0.0 || $q <= 0.0 || ($p + $q) > LOG_GAMMA_X_MAX_VALUE) { + return 0.0; + } else { + return exp(self::_logBeta($p, $q)); + } + } // function _beta() + + + /** + * Incomplete beta function + * + * @author Jaco van Kooten + * @author Paul Meagher + * + * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992). + * @param x require 0<=x<=1 + * @param p require p>0 + * @param q require q>0 + * @return 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow + */ + private static function _incompleteBeta($x, $p, $q) { + if ($x <= 0.0) { + return 0.0; + } elseif ($x >= 1.0) { + return 1.0; + } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) { + return 0.0; + } + $beta_gam = exp((0 - self::_logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x)); + if ($x < ($p + 1.0) / ($p + $q + 2.0)) { + return $beta_gam * self::_betaFraction($x, $p, $q) / $p; + } else { + return 1.0 - ($beta_gam * self::_betaFraction(1 - $x, $q, $p) / $q); + } + } // function _incompleteBeta() + + + // Function cache for _logBeta function + private static $_logBetaCache_p = 0.0; + private static $_logBetaCache_q = 0.0; + private static $_logBetaCache_result = 0.0; + + /** + * The natural logarithm of the beta function. + * @param p require p>0 + * @param q require q>0 + * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow + * @author Jaco van Kooten + */ + private static function _logBeta($p, $q) { + if ($p != self::$_logBetaCache_p || $q != self::$_logBetaCache_q) { + self::$_logBetaCache_p = $p; + self::$_logBetaCache_q = $q; + if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) { + self::$_logBetaCache_result = 0.0; + } else { + self::$_logBetaCache_result = self::_logGamma($p) + self::_logGamma($q) - self::_logGamma($p + $q); + } + } + return self::$_logBetaCache_result; + } // function _logBeta() + + + /** + * Evaluates of continued fraction part of incomplete beta function. + * Based on an idea from Numerical Recipes (W.H. Press et al, 1992). + * @author Jaco van Kooten + */ + private static function _betaFraction($x, $p, $q) { + $c = 1.0; + $sum_pq = $p + $q; + $p_plus = $p + 1.0; + $p_minus = $p - 1.0; + $h = 1.0 - $sum_pq * $x / $p_plus; + if (abs($h) < XMININ) { + $h = XMININ; + } + $h = 1.0 / $h; + $frac = $h; + $m = 1; + $delta = 0.0; + while ($m <= MAX_ITERATIONS && abs($delta-1.0) > PRECISION ) { + $m2 = 2 * $m; + // even index for d + $d = $m * ($q - $m) * $x / ( ($p_minus + $m2) * ($p + $m2)); + $h = 1.0 + $d * $h; + if (abs($h) < XMININ) { + $h = XMININ; + } + $h = 1.0 / $h; + $c = 1.0 + $d / $c; + if (abs($c) < XMININ) { + $c = XMININ; + } + $frac *= $h * $c; + // odd index for d + $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2)); + $h = 1.0 + $d * $h; + if (abs($h) < XMININ) { + $h = XMININ; + } + $h = 1.0 / $h; + $c = 1.0 + $d / $c; + if (abs($c) < XMININ) { + $c = XMININ; + } + $delta = $h * $c; + $frac *= $delta; + ++$m; + } + return $frac; + } // function _betaFraction() + + + /** + * logGamma function + * + * @version 1.1 + * @author Jaco van Kooten + * + * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher. + * + * The natural logarithm of the gamma function.
+ * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz
+ * Applied Mathematics Division
+ * Argonne National Laboratory
+ * Argonne, IL 60439
+ *

+ * References: + *

    + *
  1. W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural + * Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.
  2. + *
  3. K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.
  4. + *
  5. Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.
  6. + *
+ *

+ *

+ * From the original documentation: + *

+ *

+ * This routine calculates the LOG(GAMMA) function for a positive real argument X. + * Computation is based on an algorithm outlined in references 1 and 2. + * The program uses rational functions that theoretically approximate LOG(GAMMA) + * to at least 18 significant decimal digits. The approximation for X > 12 is from + * reference 3, while approximations for X < 12.0 are similar to those in reference + * 1, but are unpublished. The accuracy achieved depends on the arithmetic system, + * the compiler, the intrinsic functions, and proper selection of the + * machine-dependent constants. + *

+ *

+ * Error returns:
+ * The program returns the value XINF for X .LE. 0.0 or when overflow would occur. + * The computation is believed to be free of underflow and overflow. + *

+ * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305 + */ + + // Function cache for logGamma + private static $_logGammaCache_result = 0.0; + private static $_logGammaCache_x = 0.0; + + private static function _logGamma($x) { + // Log Gamma related constants + static $lg_d1 = -0.5772156649015328605195174; + static $lg_d2 = 0.4227843350984671393993777; + static $lg_d4 = 1.791759469228055000094023; + + static $lg_p1 = array( 4.945235359296727046734888, + 201.8112620856775083915565, + 2290.838373831346393026739, + 11319.67205903380828685045, + 28557.24635671635335736389, + 38484.96228443793359990269, + 26377.48787624195437963534, + 7225.813979700288197698961 ); + static $lg_p2 = array( 4.974607845568932035012064, + 542.4138599891070494101986, + 15506.93864978364947665077, + 184793.2904445632425417223, + 1088204.76946882876749847, + 3338152.967987029735917223, + 5106661.678927352456275255, + 3074109.054850539556250927 ); + static $lg_p4 = array( 14745.02166059939948905062, + 2426813.369486704502836312, + 121475557.4045093227939592, + 2663432449.630976949898078, + 29403789566.34553899906876, + 170266573776.5398868392998, + 492612579337.743088758812, + 560625185622.3951465078242 ); + + static $lg_q1 = array( 67.48212550303777196073036, + 1113.332393857199323513008, + 7738.757056935398733233834, + 27639.87074403340708898585, + 54993.10206226157329794414, + 61611.22180066002127833352, + 36351.27591501940507276287, + 8785.536302431013170870835 ); + static $lg_q2 = array( 183.0328399370592604055942, + 7765.049321445005871323047, + 133190.3827966074194402448, + 1136705.821321969608938755, + 5267964.117437946917577538, + 13467014.54311101692290052, + 17827365.30353274213975932, + 9533095.591844353613395747 ); + static $lg_q4 = array( 2690.530175870899333379843, + 639388.5654300092398984238, + 41355999.30241388052042842, + 1120872109.61614794137657, + 14886137286.78813811542398, + 101680358627.2438228077304, + 341747634550.7377132798597, + 446315818741.9713286462081 ); + + static $lg_c = array( -0.001910444077728, + 8.4171387781295e-4, + -5.952379913043012e-4, + 7.93650793500350248e-4, + -0.002777777777777681622553, + 0.08333333333333333331554247, + 0.0057083835261 ); + + // Rough estimate of the fourth root of logGamma_xBig + static $lg_frtbig = 2.25e76; + static $pnt68 = 0.6796875; + + + if ($x == self::$_logGammaCache_x) { + return self::$_logGammaCache_result; + } + $y = $x; + if ($y > 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE) { + if ($y <= EPS) { + $res = -log(y); + } elseif ($y <= 1.5) { + // --------------------- + // EPS .LT. X .LE. 1.5 + // --------------------- + if ($y < $pnt68) { + $corr = -log($y); + $xm1 = $y; + } else { + $corr = 0.0; + $xm1 = $y - 1.0; + } + if ($y <= 0.5 || $y >= $pnt68) { + $xden = 1.0; + $xnum = 0.0; + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm1 + $lg_p1[$i]; + $xden = $xden * $xm1 + $lg_q1[$i]; + } + $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden)); + } else { + $xm2 = $y - 1.0; + $xden = 1.0; + $xnum = 0.0; + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm2 + $lg_p2[$i]; + $xden = $xden * $xm2 + $lg_q2[$i]; + } + $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden)); + } + } elseif ($y <= 4.0) { + // --------------------- + // 1.5 .LT. X .LE. 4.0 + // --------------------- + $xm2 = $y - 2.0; + $xden = 1.0; + $xnum = 0.0; + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm2 + $lg_p2[$i]; + $xden = $xden * $xm2 + $lg_q2[$i]; + } + $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden)); + } elseif ($y <= 12.0) { + // ---------------------- + // 4.0 .LT. X .LE. 12.0 + // ---------------------- + $xm4 = $y - 4.0; + $xden = -1.0; + $xnum = 0.0; + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm4 + $lg_p4[$i]; + $xden = $xden * $xm4 + $lg_q4[$i]; + } + $res = $lg_d4 + $xm4 * ($xnum / $xden); + } else { + // --------------------------------- + // Evaluate for argument .GE. 12.0 + // --------------------------------- + $res = 0.0; + if ($y <= $lg_frtbig) { + $res = $lg_c[6]; + $ysq = $y * $y; + for ($i = 0; $i < 6; ++$i) + $res = $res / $ysq + $lg_c[$i]; + } + $res /= $y; + $corr = log($y); + $res = $res + log(SQRT2PI) - 0.5 * $corr; + $res += $y * ($corr - 1.0); + } + } else { + // -------------------------- + // Return for bad arguments + // -------------------------- + $res = MAX_VALUE; + } + // ------------------------------ + // Final adjustments and return + // ------------------------------ + self::$_logGammaCache_x = $x; + self::$_logGammaCache_result = $res; + return $res; + } // function _logGamma() + + + // + // Private implementation of the incomplete Gamma function + // + private static function _incompleteGamma($a,$x) { + static $max = 32; + $summer = 0; + for ($n=0; $n<=$max; ++$n) { + $divisor = $a; + for ($i=1; $i<=$n; ++$i) { + $divisor *= ($a + $i); + } + $summer += (pow($x,$n) / $divisor); + } + return pow($x,$a) * exp(0-$x) * $summer; + } // function _incompleteGamma() + + + // + // Private implementation of the Gamma function + // + private static function _gamma($data) { + if ($data == 0.0) return 0; + + static $p0 = 1.000000000190015; + static $p = array ( 1 => 76.18009172947146, + 2 => -86.50532032941677, + 3 => 24.01409824083091, + 4 => -1.231739572450155, + 5 => 1.208650973866179e-3, + 6 => -5.395239384953e-6 + ); + + $y = $x = $data; + $tmp = $x + 5.5; + $tmp -= ($x + 0.5) * log($tmp); + + $summer = $p0; + for ($j=1;$j<=6;++$j) { + $summer += ($p[$j] / ++$y); + } + return exp(0 - $tmp + log(SQRT2PI * $summer / $x)); + } // function _gamma() + + + /*************************************************************************** + * inverse_ncdf.php + * ------------------- + * begin : Friday, January 16, 2004 + * copyright : (C) 2004 Michael Nickerson + * email : nickersonm@yahoo.com + * + ***************************************************************************/ + private static function _inverse_ncdf($p) { + // Inverse ncdf approximation by Peter J. Acklam, implementation adapted to + // PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as + // a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html + // I have not checked the accuracy of this implementation. Be aware that PHP + // will truncate the coeficcients to 14 digits. + + // You have permission to use and distribute this function freely for + // whatever purpose you want, but please show common courtesy and give credit + // where credit is due. + + // Input paramater is $p - probability - where 0 < p < 1. + + // Coefficients in rational approximations + static $a = array( 1 => -3.969683028665376e+01, + 2 => 2.209460984245205e+02, + 3 => -2.759285104469687e+02, + 4 => 1.383577518672690e+02, + 5 => -3.066479806614716e+01, + 6 => 2.506628277459239e+00 + ); + + static $b = array( 1 => -5.447609879822406e+01, + 2 => 1.615858368580409e+02, + 3 => -1.556989798598866e+02, + 4 => 6.680131188771972e+01, + 5 => -1.328068155288572e+01 + ); + + static $c = array( 1 => -7.784894002430293e-03, + 2 => -3.223964580411365e-01, + 3 => -2.400758277161838e+00, + 4 => -2.549732539343734e+00, + 5 => 4.374664141464968e+00, + 6 => 2.938163982698783e+00 + ); + + static $d = array( 1 => 7.784695709041462e-03, + 2 => 3.224671290700398e-01, + 3 => 2.445134137142996e+00, + 4 => 3.754408661907416e+00 + ); + + // Define lower and upper region break-points. + $p_low = 0.02425; //Use lower region approx. below this + $p_high = 1 - $p_low; //Use upper region approx. above this + + if (0 < $p && $p < $p_low) { + // Rational approximation for lower region. + $q = sqrt(-2 * log($p)); + return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / + (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); + } elseif ($p_low <= $p && $p <= $p_high) { + // Rational approximation for central region. + $q = $p - 0.5; + $r = $q * $q; + return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q / + ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1); + } elseif ($p_high < $p && $p < 1) { + // Rational approximation for upper region. + $q = sqrt(-2 * log(1 - $p)); + return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / + (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); + } + // If 0 < p < 1, return a null value + return PHPExcel_Calculation_Functions::NULL(); + } // function _inverse_ncdf() + + + private static function _inverse_ncdf2($prob) { + // Approximation of inverse standard normal CDF developed by + // B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58. + + $a1 = 2.50662823884; + $a2 = -18.61500062529; + $a3 = 41.39119773534; + $a4 = -25.44106049637; + + $b1 = -8.4735109309; + $b2 = 23.08336743743; + $b3 = -21.06224101826; + $b4 = 3.13082909833; + + $c1 = 0.337475482272615; + $c2 = 0.976169019091719; + $c3 = 0.160797971491821; + $c4 = 2.76438810333863E-02; + $c5 = 3.8405729373609E-03; + $c6 = 3.951896511919E-04; + $c7 = 3.21767881768E-05; + $c8 = 2.888167364E-07; + $c9 = 3.960315187E-07; + + $y = $prob - 0.5; + if (abs($y) < 0.42) { + $z = ($y * $y); + $z = $y * ((($a4 * $z + $a3) * $z + $a2) * $z + $a1) / (((($b4 * $z + $b3) * $z + $b2) * $z + $b1) * $z + 1); + } else { + if ($y > 0) { + $z = log(-log(1 - $prob)); + } else { + $z = log(-log($prob)); + } + $z = $c1 + $z * ($c2 + $z * ($c3 + $z * ($c4 + $z * ($c5 + $z * ($c6 + $z * ($c7 + $z * ($c8 + $z * $c9))))))); + if ($y < 0) { + $z = -$z; + } + } + return $z; + } // function _inverse_ncdf2() + + + private static function _inverse_ncdf3($p) { + // ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3. + // Produces the normal deviate Z corresponding to a given lower + // tail area of P; Z is accurate to about 1 part in 10**16. + // + // This is a PHP version of the original FORTRAN code that can + // be found at http://lib.stat.cmu.edu/apstat/ + $split1 = 0.425; + $split2 = 5; + $const1 = 0.180625; + $const2 = 1.6; + + // coefficients for p close to 0.5 + $a0 = 3.3871328727963666080; + $a1 = 1.3314166789178437745E+2; + $a2 = 1.9715909503065514427E+3; + $a3 = 1.3731693765509461125E+4; + $a4 = 4.5921953931549871457E+4; + $a5 = 6.7265770927008700853E+4; + $a6 = 3.3430575583588128105E+4; + $a7 = 2.5090809287301226727E+3; + + $b1 = 4.2313330701600911252E+1; + $b2 = 6.8718700749205790830E+2; + $b3 = 5.3941960214247511077E+3; + $b4 = 2.1213794301586595867E+4; + $b5 = 3.9307895800092710610E+4; + $b6 = 2.8729085735721942674E+4; + $b7 = 5.2264952788528545610E+3; + + // coefficients for p not close to 0, 0.5 or 1. + $c0 = 1.42343711074968357734; + $c1 = 4.63033784615654529590; + $c2 = 5.76949722146069140550; + $c3 = 3.64784832476320460504; + $c4 = 1.27045825245236838258; + $c5 = 2.41780725177450611770E-1; + $c6 = 2.27238449892691845833E-2; + $c7 = 7.74545014278341407640E-4; + + $d1 = 2.05319162663775882187; + $d2 = 1.67638483018380384940; + $d3 = 6.89767334985100004550E-1; + $d4 = 1.48103976427480074590E-1; + $d5 = 1.51986665636164571966E-2; + $d6 = 5.47593808499534494600E-4; + $d7 = 1.05075007164441684324E-9; + + // coefficients for p near 0 or 1. + $e0 = 6.65790464350110377720; + $e1 = 5.46378491116411436990; + $e2 = 1.78482653991729133580; + $e3 = 2.96560571828504891230E-1; + $e4 = 2.65321895265761230930E-2; + $e5 = 1.24266094738807843860E-3; + $e6 = 2.71155556874348757815E-5; + $e7 = 2.01033439929228813265E-7; + + $f1 = 5.99832206555887937690E-1; + $f2 = 1.36929880922735805310E-1; + $f3 = 1.48753612908506148525E-2; + $f4 = 7.86869131145613259100E-4; + $f5 = 1.84631831751005468180E-5; + $f6 = 1.42151175831644588870E-7; + $f7 = 2.04426310338993978564E-15; + + $q = $p - 0.5; + + // computation for p close to 0.5 + if (abs($q) <= split1) { + $R = $const1 - $q * $q; + $z = $q * ((((((($a7 * $R + $a6) * $R + $a5) * $R + $a4) * $R + $a3) * $R + $a2) * $R + $a1) * $R + $a0) / + ((((((($b7 * $R + $b6) * $R + $b5) * $R + $b4) * $R + $b3) * $R + $b2) * $R + $b1) * $R + 1); + } else { + if ($q < 0) { + $R = $p; + } else { + $R = 1 - $p; + } + $R = pow(-log($R),2); + + // computation for p not close to 0, 0.5 or 1. + If ($R <= $split2) { + $R = $R - $const2; + $z = ((((((($c7 * $R + $c6) * $R + $c5) * $R + $c4) * $R + $c3) * $R + $c2) * $R + $c1) * $R + $c0) / + ((((((($d7 * $R + $d6) * $R + $d5) * $R + $d4) * $R + $d3) * $R + $d2) * $R + $d1) * $R + 1); + } else { + // computation for p near 0 or 1. + $R = $R - $split2; + $z = ((((((($e7 * $R + $e6) * $R + $e5) * $R + $e4) * $R + $e3) * $R + $e2) * $R + $e1) * $R + $e0) / + ((((((($f7 * $R + $f6) * $R + $f5) * $R + $f4) * $R + $f3) * $R + $f2) * $R + $f1) * $R + 1); + } + if ($q < 0) { + $z = -$z; + } + } + return $z; + } // function _inverse_ncdf3() + + + /** + * AVEDEV + * + * Returns the average of the absolute deviations of data points from their mean. + * AVEDEV is a measure of the variability in a data set. + * + * Excel Function: + * AVEDEV(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function AVEDEV() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + + // Return value + $returnValue = null; + + $aMean = self::AVERAGE($aArgs); + if ($aMean != PHPExcel_Calculation_Functions::DIV0()) { + $aCount = 0; + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) { + $arg = (integer) $arg; + } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if (is_null($returnValue)) { + $returnValue = abs($arg - $aMean); + } else { + $returnValue += abs($arg - $aMean); + } + ++$aCount; + } + } + + // Return + if ($aCount == 0) { + return PHPExcel_Calculation_Functions::DIV0(); + } + return $returnValue / $aCount; + } + return PHPExcel_Calculation_Functions::NaN(); + } // function AVEDEV() + + + /** + * AVERAGE + * + * Returns the average (arithmetic mean) of the arguments + * + * Excel Function: + * AVERAGE(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function AVERAGE() { + $returnValue = $aCount = 0; + + // Loop through arguments + foreach (PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) { + if ((is_bool($arg)) && + ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) { + $arg = (integer) $arg; + } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if (is_null($returnValue)) { + $returnValue = $arg; + } else { + $returnValue += $arg; + } + ++$aCount; + } + } + + // Return + if ($aCount > 0) { + return $returnValue / $aCount; + } else { + return PHPExcel_Calculation_Functions::DIV0(); + } + } // function AVERAGE() + + + /** + * AVERAGEA + * + * Returns the average of its arguments, including numbers, text, and logical values + * + * Excel Function: + * AVERAGEA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function AVERAGEA() { + // Return value + $returnValue = null; + + $aCount = 0; + // Loop through arguments + foreach (PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) { + if ((is_bool($arg)) && + (!PHPExcel_Calculation_Functions::isMatrixValue($k))) { + } else { + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + if (is_bool($arg)) { + $arg = (integer) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + if (is_null($returnValue)) { + $returnValue = $arg; + } else { + $returnValue += $arg; + } + ++$aCount; + } + } + } + + // Return + if ($aCount > 0) { + return $returnValue / $aCount; + } else { + return PHPExcel_Calculation_Functions::DIV0(); + } + } // function AVERAGEA() + + + /** + * AVERAGEIF + * + * Returns the average value from a range of cells that contain numbers within the list of arguments + * + * Excel Function: + * AVERAGEIF(value1[,value2[, ...]],condition) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @param string $condition The criteria that defines which cells will be checked. + * @return float + */ + public static function AVERAGEIF($aArgs,$condition,$averageArgs = array()) { + // Return value + $returnValue = 0; + + $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs); + $averageArgs = PHPExcel_Calculation_Functions::flattenArray($averageArgs); + if (count($averageArgs) == 0) { + $averageArgs = $aArgs; + } + $condition = PHPExcel_Calculation_Functions::_ifCondition($condition); + // Loop through arguments + $aCount = 0; + foreach ($aArgs as $key => $arg) { + if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } + $testCondition = '='.$arg.$condition; + if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { + if ((is_null($returnValue)) || ($arg > $returnValue)) { + $returnValue += $arg; + ++$aCount; + } + } + } + + // Return + if ($aCount > 0) { + return $returnValue / $aCount; + } else { + return PHPExcel_Calculation_Functions::DIV0(); + } + } // function AVERAGEIF() + + + /** + * BETADIST + * + * Returns the beta distribution. + * + * @param float $value Value at which you want to evaluate the distribution + * @param float $alpha Parameter to the distribution + * @param float $beta Parameter to the distribution + * @param boolean $cumulative + * @return float + * + */ + public static function BETADIST($value,$alpha,$beta,$rMin=0,$rMax=1) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha); + $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta); + $rMin = PHPExcel_Calculation_Functions::flattenSingleValue($rMin); + $rMax = PHPExcel_Calculation_Functions::flattenSingleValue($rMax); + + if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { + if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($rMin > $rMax) { + $tmp = $rMin; + $rMin = $rMax; + $rMax = $tmp; + } + $value -= $rMin; + $value /= ($rMax - $rMin); + return self::_incompleteBeta($value,$alpha,$beta); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function BETADIST() + + + /** + * BETAINV + * + * Returns the inverse of the beta distribution. + * + * @param float $probability Probability at which you want to evaluate the distribution + * @param float $alpha Parameter to the distribution + * @param float $beta Parameter to the distribution + * @param boolean $cumulative + * @return float + * + */ + public static function BETAINV($probability,$alpha,$beta,$rMin=0,$rMax=1) { + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha); + $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta); + $rMin = PHPExcel_Calculation_Functions::flattenSingleValue($rMin); + $rMax = PHPExcel_Calculation_Functions::flattenSingleValue($rMax); + + if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { + if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($rMin > $rMax) { + $tmp = $rMin; + $rMin = $rMax; + $rMax = $tmp; + } + $a = 0; + $b = 2; + + $i = 0; + while ((($b - $a) > PRECISION) && ($i++ < MAX_ITERATIONS)) { + $guess = ($a + $b) / 2; + $result = self::BETADIST($guess, $alpha, $beta); + if (($result == $probability) || ($result == 0)) { + $b = $a; + } elseif ($result > $probability) { + $b = $guess; + } else { + $a = $guess; + } + } + if ($i == MAX_ITERATIONS) { + return PHPExcel_Calculation_Functions::NA(); + } + return round($rMin + $guess * ($rMax - $rMin),12); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function BETAINV() + + + /** + * BINOMDIST + * + * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with + * a fixed number of tests or trials, when the outcomes of any trial are only success or failure, + * when trials are independent, and when the probability of success is constant throughout the + * experiment. For example, BINOMDIST can calculate the probability that two of the next three + * babies born are male. + * + * @param float $value Number of successes in trials + * @param float $trials Number of trials + * @param float $probability Probability of success on each trial + * @param boolean $cumulative + * @return float + * + * @todo Cumulative distribution function + * + */ + public static function BINOMDIST($value, $trials, $probability, $cumulative) { + $value = floor(PHPExcel_Calculation_Functions::flattenSingleValue($value)); + $trials = floor(PHPExcel_Calculation_Functions::flattenSingleValue($trials)); + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + + if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) { + if (($value < 0) || ($value > $trials)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($probability < 0) || ($probability > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ((is_numeric($cumulative)) || (is_bool($cumulative))) { + if ($cumulative) { + $summer = 0; + for ($i = 0; $i <= $value; ++$i) { + $summer += PHPExcel_Calculation_MathTrig::COMBIN($trials,$i) * pow($probability,$i) * pow(1 - $probability,$trials - $i); + } + return $summer; + } else { + return PHPExcel_Calculation_MathTrig::COMBIN($trials,$value) * pow($probability,$value) * pow(1 - $probability,$trials - $value) ; + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function BINOMDIST() + + + /** + * CHIDIST + * + * Returns the one-tailed probability of the chi-squared distribution. + * + * @param float $value Value for the function + * @param float $degrees degrees of freedom + * @return float + */ + public static function CHIDIST($value, $degrees) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees)); + + if ((is_numeric($value)) && (is_numeric($degrees))) { + if ($degrees < 1) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($value < 0) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + return 1; + } + return PHPExcel_Calculation_Functions::NaN(); + } + return 1 - (self::_incompleteGamma($degrees/2,$value/2) / self::_gamma($degrees/2)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function CHIDIST() + + + /** + * CHIINV + * + * Returns the one-tailed probability of the chi-squared distribution. + * + * @param float $probability Probability for the function + * @param float $degrees degrees of freedom + * @return float + */ + public static function CHIINV($probability, $degrees) { + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees)); + + if ((is_numeric($probability)) && (is_numeric($degrees))) { + + $xLo = 100; + $xHi = 0; + + $x = $xNew = 1; + $dx = 1; + $i = 0; + + while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { + // Apply Newton-Raphson step + $result = self::CHIDIST($x, $degrees); + $error = $result - $probability; + if ($error == 0.0) { + $dx = 0; + } elseif ($error < 0.0) { + $xLo = $x; + } else { + $xHi = $x; + } + // Avoid division by zero + if ($result != 0.0) { + $dx = $error / $result; + $xNew = $x - $dx; + } + // If the NR fails to converge (which for example may be the + // case if the initial guess is too rough) we apply a bisection + // step to determine a more narrow interval around the root. + if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { + $xNew = ($xLo + $xHi) / 2; + $dx = $xNew - $x; + } + $x = $xNew; + } + if ($i == MAX_ITERATIONS) { + return PHPExcel_Calculation_Functions::NA(); + } + return round($x,12); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function CHIINV() + + + /** + * CONFIDENCE + * + * Returns the confidence interval for a population mean + * + * @param float $alpha + * @param float $stdDev Standard Deviation + * @param float $size + * @return float + * + */ + public static function CONFIDENCE($alpha,$stdDev,$size) { + $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha); + $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev); + $size = floor(PHPExcel_Calculation_Functions::flattenSingleValue($size)); + + if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) { + if (($alpha <= 0) || ($alpha >= 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($stdDev <= 0) || ($size < 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function CONFIDENCE() + + + /** + * CORREL + * + * Returns covariance, the average of the products of deviations for each data point pair. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @return float + */ + public static function CORREL($yValues,$xValues=null) { + if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) { + return PHPExcel_Calculation_Functions::VALUE(); + } + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); + return $bestFitLinear->getCorrelation(); + } // function CORREL() + + + /** + * COUNT + * + * Counts the number of cells that contain numbers within the list of arguments + * + * Excel Function: + * COUNT(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return int + */ + public static function COUNT() { + // Return value + $returnValue = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) { + $arg = (integer) $arg; + } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + ++$returnValue; + } + } + + // Return + return $returnValue; + } // function COUNT() + + + /** + * COUNTA + * + * Counts the number of cells that are not empty within the list of arguments + * + * Excel Function: + * COUNTA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return int + */ + public static function COUNTA() { + // Return value + $returnValue = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + // Is it a numeric, boolean or string value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + ++$returnValue; + } + } + + // Return + return $returnValue; + } // function COUNTA() + + + /** + * COUNTBLANK + * + * Counts the number of empty cells within the list of arguments + * + * Excel Function: + * COUNTBLANK(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return int + */ + public static function COUNTBLANK() { + // Return value + $returnValue = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + // Is it a blank cell? + if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) { + ++$returnValue; + } + } + + // Return + return $returnValue; + } // function COUNTBLANK() + + + /** + * COUNTIF + * + * Counts the number of cells that contain numbers within the list of arguments + * + * Excel Function: + * COUNTIF(value1[,value2[, ...]],condition) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @param string $condition The criteria that defines which cells will be counted. + * @return int + */ + public static function COUNTIF($aArgs,$condition) { + // Return value + $returnValue = 0; + + $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs); + $condition = PHPExcel_Calculation_Functions::_ifCondition($condition); + // Loop through arguments + foreach ($aArgs as $arg) { + if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } + $testCondition = '='.$arg.$condition; + if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { + // Is it a value within our criteria + ++$returnValue; + } + } + + // Return + return $returnValue; + } // function COUNTIF() + + + /** + * COVAR + * + * Returns covariance, the average of the products of deviations for each data point pair. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @return float + */ + public static function COVAR($yValues,$xValues) { + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); + return $bestFitLinear->getCovariance(); + } // function COVAR() + + + /** + * CRITBINOM + * + * Returns the smallest value for which the cumulative binomial distribution is greater + * than or equal to a criterion value + * + * See http://support.microsoft.com/kb/828117/ for details of the algorithm used + * + * @param float $trials number of Bernoulli trials + * @param float $probability probability of a success on each trial + * @param float $alpha criterion value + * @return int + * + * @todo Warning. This implementation differs from the algorithm detailed on the MS + * web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess + * This eliminates a potential endless loop error, but may have an adverse affect on the + * accuracy of the function (although all my tests have so far returned correct results). + * + */ + public static function CRITBINOM($trials, $probability, $alpha) { + $trials = floor(PHPExcel_Calculation_Functions::flattenSingleValue($trials)); + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha); + + if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) { + if ($trials < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($probability < 0) || ($probability > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($alpha < 0) || ($alpha > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($alpha <= 0.5) { + $t = sqrt(log(1 / ($alpha * $alpha))); + $trialsApprox = 0 - ($t + (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t)); + } else { + $t = sqrt(log(1 / pow(1 - $alpha,2))); + $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t); + } + $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability))); + if ($Guess < 0) { + $Guess = 0; + } elseif ($Guess > $trials) { + $Guess = $trials; + } + + $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0; + $EssentiallyZero = 10e-12; + + $m = floor($trials * $probability); + ++$TotalUnscaledProbability; + if ($m == $Guess) { ++$UnscaledPGuess; } + if ($m <= $Guess) { ++$UnscaledCumPGuess; } + + $PreviousValue = 1; + $Done = False; + $k = $m + 1; + while ((!$Done) && ($k <= $trials)) { + $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability)); + $TotalUnscaledProbability += $CurrentValue; + if ($k == $Guess) { $UnscaledPGuess += $CurrentValue; } + if ($k <= $Guess) { $UnscaledCumPGuess += $CurrentValue; } + if ($CurrentValue <= $EssentiallyZero) { $Done = True; } + $PreviousValue = $CurrentValue; + ++$k; + } + + $PreviousValue = 1; + $Done = False; + $k = $m - 1; + while ((!$Done) && ($k >= 0)) { + $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability); + $TotalUnscaledProbability += $CurrentValue; + if ($k == $Guess) { $UnscaledPGuess += $CurrentValue; } + if ($k <= $Guess) { $UnscaledCumPGuess += $CurrentValue; } + if ($CurrentValue <= $EssentiallyZero) { $Done = True; } + $PreviousValue = $CurrentValue; + --$k; + } + + $PGuess = $UnscaledPGuess / $TotalUnscaledProbability; + $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability; + +// $CumPGuessMinus1 = $CumPGuess - $PGuess; + $CumPGuessMinus1 = $CumPGuess - 1; + + while (True) { + if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) { + return $Guess; + } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) { + $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability); + $CumPGuessMinus1 = $CumPGuess; + $CumPGuess = $CumPGuess + $PGuessPlus1; + $PGuess = $PGuessPlus1; + ++$Guess; + } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) { + $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability; + $CumPGuess = $CumPGuessMinus1; + $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess; + $PGuess = $PGuessMinus1; + --$Guess; + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function CRITBINOM() + + + /** + * DEVSQ + * + * Returns the sum of squares of deviations of data points from their sample mean. + * + * Excel Function: + * DEVSQ(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function DEVSQ() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + + // Return value + $returnValue = null; + + $aMean = self::AVERAGE($aArgs); + if ($aMean != PHPExcel_Calculation_Functions::DIV0()) { + $aCount = -1; + foreach ($aArgs as $k => $arg) { + // Is it a numeric value? + if ((is_bool($arg)) && + ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) { + $arg = (integer) $arg; + } + if ((is_numeric($arg)) && (!is_string($arg))) { + if (is_null($returnValue)) { + $returnValue = pow(($arg - $aMean),2); + } else { + $returnValue += pow(($arg - $aMean),2); + } + ++$aCount; + } + } + + // Return + if (is_null($returnValue)) { + return PHPExcel_Calculation_Functions::NaN(); + } else { + return $returnValue; + } + } + return self::NA(); + } // function DEVSQ() + + + /** + * EXPONDIST + * + * Returns the exponential distribution. Use EXPONDIST to model the time between events, + * such as how long an automated bank teller takes to deliver cash. For example, you can + * use EXPONDIST to determine the probability that the process takes at most 1 minute. + * + * @param float $value Value of the function + * @param float $lambda The parameter value + * @param boolean $cumulative + * @return float + */ + public static function EXPONDIST($value, $lambda, $cumulative) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $lambda = PHPExcel_Calculation_Functions::flattenSingleValue($lambda); + $cumulative = PHPExcel_Calculation_Functions::flattenSingleValue($cumulative); + + if ((is_numeric($value)) && (is_numeric($lambda))) { + if (($value < 0) || ($lambda < 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ((is_numeric($cumulative)) || (is_bool($cumulative))) { + if ($cumulative) { + return 1 - exp(0-$value*$lambda); + } else { + return $lambda * exp(0-$value*$lambda); + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function EXPONDIST() + + + /** + * FISHER + * + * Returns the Fisher transformation at x. This transformation produces a function that + * is normally distributed rather than skewed. Use this function to perform hypothesis + * testing on the correlation coefficient. + * + * @param float $value + * @return float + */ + public static function FISHER($value) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + + if (is_numeric($value)) { + if (($value <= -1) || ($value >= 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return 0.5 * log((1+$value)/(1-$value)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function FISHER() + + + /** + * FISHERINV + * + * Returns the inverse of the Fisher transformation. Use this transformation when + * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then + * FISHERINV(y) = x. + * + * @param float $value + * @return float + */ + public static function FISHERINV($value) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + + if (is_numeric($value)) { + return (exp(2 * $value) - 1) / (exp(2 * $value) + 1); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function FISHERINV() + + + /** + * FORECAST + * + * Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value. + * + * @param float Value of X for which we want to find Y + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @return float + */ + public static function FORECAST($xValue,$yValues,$xValues) { + $xValue = PHPExcel_Calculation_Functions::flattenSingleValue($xValue); + if (!is_numeric($xValue)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); + return $bestFitLinear->getValueOfYForX($xValue); + } // function FORECAST() + + + /** + * GAMMADIST + * + * Returns the gamma distribution. + * + * @param float $value Value at which you want to evaluate the distribution + * @param float $a Parameter to the distribution + * @param float $b Parameter to the distribution + * @param boolean $cumulative + * @return float + * + */ + public static function GAMMADIST($value,$a,$b,$cumulative) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $a = PHPExcel_Calculation_Functions::flattenSingleValue($a); + $b = PHPExcel_Calculation_Functions::flattenSingleValue($b); + + if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) { + if (($value < 0) || ($a <= 0) || ($b <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ((is_numeric($cumulative)) || (is_bool($cumulative))) { + if ($cumulative) { + return self::_incompleteGamma($a,$value / $b) / self::_gamma($a); + } else { + return (1 / (pow($b,$a) * self::_gamma($a))) * pow($value,$a-1) * exp(0-($value / $b)); + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function GAMMADIST() + + + /** + * GAMMAINV + * + * Returns the inverse of the beta distribution. + * + * @param float $probability Probability at which you want to evaluate the distribution + * @param float $alpha Parameter to the distribution + * @param float $beta Parameter to the distribution + * @return float + * + */ + public static function GAMMAINV($probability,$alpha,$beta) { + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha); + $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta); + + if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) { + if (($alpha <= 0) || ($beta <= 0) || ($probability < 0) || ($probability > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $xLo = 0; + $xHi = $alpha * $beta * 5; + + $x = $xNew = 1; + $error = $pdf = 0; + $dx = 1024; + $i = 0; + + while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { + // Apply Newton-Raphson step + $error = self::GAMMADIST($x, $alpha, $beta, True) - $probability; + if ($error < 0.0) { + $xLo = $x; + } else { + $xHi = $x; + } + $pdf = self::GAMMADIST($x, $alpha, $beta, False); + // Avoid division by zero + if ($pdf != 0.0) { + $dx = $error / $pdf; + $xNew = $x - $dx; + } + // If the NR fails to converge (which for example may be the + // case if the initial guess is too rough) we apply a bisection + // step to determine a more narrow interval around the root. + if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) { + $xNew = ($xLo + $xHi) / 2; + $dx = $xNew - $x; + } + $x = $xNew; + } + if ($i == MAX_ITERATIONS) { + return PHPExcel_Calculation_Functions::NA(); + } + return $x; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function GAMMAINV() + + + /** + * GAMMALN + * + * Returns the natural logarithm of the gamma function. + * + * @param float $value + * @return float + */ + public static function GAMMALN($value) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + + if (is_numeric($value)) { + if ($value <= 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return log(self::_gamma($value)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function GAMMALN() + + + /** + * GEOMEAN + * + * Returns the geometric mean of an array or range of positive data. For example, you + * can use GEOMEAN to calculate average growth rate given compound interest with + * variable rates. + * + * Excel Function: + * GEOMEAN(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function GEOMEAN() { + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + $aMean = PHPExcel_Calculation_MathTrig::PRODUCT($aArgs); + if (is_numeric($aMean) && ($aMean > 0)) { + $aCount = self::COUNT($aArgs) ; + if (self::MIN($aArgs) > 0) { + return pow($aMean, (1 / $aCount)); + } + } + return PHPExcel_Calculation_Functions::NaN(); + } // GEOMEAN() + + + /** + * GROWTH + * + * Returns values along a predicted emponential trend + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @param array of mixed Values of X for which we want to find Y + * @param boolean A logical value specifying whether to force the intersect to equal 0. + * @return array of float + */ + public static function GROWTH($yValues,$xValues=array(),$newValues=array(),$const=True) { + $yValues = PHPExcel_Calculation_Functions::flattenArray($yValues); + $xValues = PHPExcel_Calculation_Functions::flattenArray($xValues); + $newValues = PHPExcel_Calculation_Functions::flattenArray($newValues); + $const = (is_null($const)) ? True : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const); + + $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const); + if (count($newValues) == 0) { + $newValues = $bestFitExponential->getXValues(); + } + + $returnArray = array(); + foreach($newValues as $xValue) { + $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue); + } + + return $returnArray; + } // function GROWTH() + + + /** + * HARMEAN + * + * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the + * arithmetic mean of reciprocals. + * + * Excel Function: + * HARMEAN(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function HARMEAN() { + // Return value + $returnValue = PHPExcel_Calculation_Functions::NA(); + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + if (self::MIN($aArgs) < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + $aCount = 0; + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if ($arg <= 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (is_null($returnValue)) { + $returnValue = (1 / $arg); + } else { + $returnValue += (1 / $arg); + } + ++$aCount; + } + } + + // Return + if ($aCount > 0) { + return 1 / ($returnValue / $aCount); + } else { + return $returnValue; + } + } // function HARMEAN() + + + /** + * HYPGEOMDIST + * + * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of + * sample successes, given the sample size, population successes, and population size. + * + * @param float $sampleSuccesses Number of successes in the sample + * @param float $sampleNumber Size of the sample + * @param float $populationSuccesses Number of successes in the population + * @param float $populationNumber Population size + * @return float + * + */ + public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber) { + $sampleSuccesses = floor(PHPExcel_Calculation_Functions::flattenSingleValue($sampleSuccesses)); + $sampleNumber = floor(PHPExcel_Calculation_Functions::flattenSingleValue($sampleNumber)); + $populationSuccesses = floor(PHPExcel_Calculation_Functions::flattenSingleValue($populationSuccesses)); + $populationNumber = floor(PHPExcel_Calculation_Functions::flattenSingleValue($populationNumber)); + + if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) { + if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return PHPExcel_Calculation_MathTrig::COMBIN($populationSuccesses,$sampleSuccesses) * + PHPExcel_Calculation_MathTrig::COMBIN($populationNumber - $populationSuccesses,$sampleNumber - $sampleSuccesses) / + PHPExcel_Calculation_MathTrig::COMBIN($populationNumber,$sampleNumber); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function HYPGEOMDIST() + + + /** + * INTERCEPT + * + * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @return float + */ + public static function INTERCEPT($yValues,$xValues) { + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); + return $bestFitLinear->getIntersect(); + } // function INTERCEPT() + + + /** + * KURT + * + * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness + * or flatness of a distribution compared with the normal distribution. Positive + * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a + * relatively flat distribution. + * + * @param array Data Series + * @return float + */ + public static function KURT() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + $mean = self::AVERAGE($aArgs); + $stdDev = self::STDEV($aArgs); + + if ($stdDev > 0) { + $count = $summer = 0; + // Loop through arguments + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + (!PHPExcel_Calculation_Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $summer += pow((($arg - $mean) / $stdDev),4) ; + ++$count; + } + } + } + + // Return + if ($count > 3) { + return $summer * ($count * ($count+1) / (($count-1) * ($count-2) * ($count-3))) - (3 * pow($count-1,2) / (($count-2) * ($count-3))); + } + } + return PHPExcel_Calculation_Functions::DIV0(); + } // function KURT() + + + /** + * LARGE + * + * Returns the nth largest value in a data set. You can use this function to + * select a value based on its relative standing. + * + * Excel Function: + * LARGE(value1[,value2[, ...]],entry) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @param int $entry Position (ordered from the largest) in the array or range of data to return + * @return float + * + */ + public static function LARGE() { + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + // Calculate + $entry = floor(array_pop($aArgs)); + + if ((is_numeric($entry)) && (!is_string($entry))) { + $mArgs = array(); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $mArgs[] = $arg; + } + } + $count = self::COUNT($mArgs); + $entry = floor(--$entry); + if (($entry < 0) || ($entry >= $count) || ($count == 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + rsort($mArgs); + return $mArgs[$entry]; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function LARGE() + + + /** + * LINEST + * + * Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data, + * and then returns an array that describes the line. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @param boolean A logical value specifying whether to force the intersect to equal 0. + * @param boolean A logical value specifying whether to return additional regression statistics. + * @return array + */ + public static function LINEST($yValues,$xValues=null,$const=True,$stats=False) { + $const = (is_null($const)) ? True : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const); + $stats = (is_null($stats)) ? False : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($stats); + if (is_null($xValues)) $xValues = range(1,count(PHPExcel_Calculation_Functions::flattenArray($yValues))); + + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return 0; + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const); + if ($stats) { + return array( array( $bestFitLinear->getSlope(), + $bestFitLinear->getSlopeSE(), + $bestFitLinear->getGoodnessOfFit(), + $bestFitLinear->getF(), + $bestFitLinear->getSSRegression(), + ), + array( $bestFitLinear->getIntersect(), + $bestFitLinear->getIntersectSE(), + $bestFitLinear->getStdevOfResiduals(), + $bestFitLinear->getDFResiduals(), + $bestFitLinear->getSSResiduals() + ) + ); + } else { + return array( $bestFitLinear->getSlope(), + $bestFitLinear->getIntersect() + ); + } + } // function LINEST() + + + /** + * LOGEST + * + * Calculates an exponential curve that best fits the X and Y data series, + * and then returns an array that describes the line. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @param boolean A logical value specifying whether to force the intersect to equal 0. + * @param boolean A logical value specifying whether to return additional regression statistics. + * @return array + */ + public static function LOGEST($yValues,$xValues=null,$const=True,$stats=False) { + $const = (is_null($const)) ? True : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const); + $stats = (is_null($stats)) ? False : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($stats); + if (is_null($xValues)) $xValues = range(1,count(PHPExcel_Calculation_Functions::flattenArray($yValues))); + + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + foreach($yValues as $value) { + if ($value <= 0.0) { + return PHPExcel_Calculation_Functions::NaN(); + } + } + + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return 1; + } + + $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL,$yValues,$xValues,$const); + if ($stats) { + return array( array( $bestFitExponential->getSlope(), + $bestFitExponential->getSlopeSE(), + $bestFitExponential->getGoodnessOfFit(), + $bestFitExponential->getF(), + $bestFitExponential->getSSRegression(), + ), + array( $bestFitExponential->getIntersect(), + $bestFitExponential->getIntersectSE(), + $bestFitExponential->getStdevOfResiduals(), + $bestFitExponential->getDFResiduals(), + $bestFitExponential->getSSResiduals() + ) + ); + } else { + return array( $bestFitExponential->getSlope(), + $bestFitExponential->getIntersect() + ); + } + } // function LOGEST() + + + /** + * LOGINV + * + * Returns the inverse of the normal cumulative distribution + * + * @param float $value + * @return float + * + * @todo Try implementing P J Acklam's refinement algorithm for greater + * accuracy if I can get my head round the mathematics + * (as described at) http://home.online.no/~pjacklam/notes/invnorm/ + */ + public static function LOGINV($probability, $mean, $stdDev) { + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean); + $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev); + + if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) { + if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return exp($mean + $stdDev * self::NORMSINV($probability)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function LOGINV() + + + /** + * LOGNORMDIST + * + * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed + * with parameters mean and standard_dev. + * + * @param float $value + * @return float + */ + public static function LOGNORMDIST($value, $mean, $stdDev) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean); + $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev); + + if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { + if (($value <= 0) || ($stdDev <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return self::NORMSDIST((log($value) - $mean) / $stdDev); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function LOGNORMDIST() + + + /** + * MAX + * + * MAX returns the value of the element of the values passed that has the highest value, + * with negative numbers considered smaller than positive numbers. + * + * Excel Function: + * MAX(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function MAX() { + // Return value + $returnValue = null; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if ((is_null($returnValue)) || ($arg > $returnValue)) { + $returnValue = $arg; + } + } + } + + // Return + if(is_null($returnValue)) { + return 0; + } + return $returnValue; + } // function MAX() + + + /** + * MAXA + * + * Returns the greatest value in a list of arguments, including numbers, text, and logical values + * + * Excel Function: + * MAXA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function MAXA() { + // Return value + $returnValue = null; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + if (is_bool($arg)) { + $arg = (integer) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + if ((is_null($returnValue)) || ($arg > $returnValue)) { + $returnValue = $arg; + } + } + } + + // Return + if(is_null($returnValue)) { + return 0; + } + return $returnValue; + } // function MAXA() + + + /** + * MAXIF + * + * Counts the maximum value within a range of cells that contain numbers within the list of arguments + * + * Excel Function: + * MAXIF(value1[,value2[, ...]],condition) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @param string $condition The criteria that defines which cells will be checked. + * @return float + */ + public static function MAXIF($aArgs,$condition,$sumArgs = array()) { + // Return value + $returnValue = null; + + $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs); + $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs); + if (count($sumArgs) == 0) { + $sumArgs = $aArgs; + } + $condition = PHPExcel_Calculation_Functions::_ifCondition($condition); + // Loop through arguments + foreach ($aArgs as $key => $arg) { + if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } + $testCondition = '='.$arg.$condition; + if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { + if ((is_null($returnValue)) || ($arg > $returnValue)) { + $returnValue = $arg; + } + } + } + + // Return + return $returnValue; + } // function MAXIF() + + + /** + * MEDIAN + * + * Returns the median of the given numbers. The median is the number in the middle of a set of numbers. + * + * Excel Function: + * MEDIAN(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function MEDIAN() { + // Return value + $returnValue = PHPExcel_Calculation_Functions::NaN(); + + $mArgs = array(); + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $mArgs[] = $arg; + } + } + + $mValueCount = count($mArgs); + if ($mValueCount > 0) { + sort($mArgs,SORT_NUMERIC); + $mValueCount = $mValueCount / 2; + if ($mValueCount == floor($mValueCount)) { + $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2; + } else { + $mValueCount == floor($mValueCount); + $returnValue = $mArgs[$mValueCount]; + } + } + + // Return + return $returnValue; + } // function MEDIAN() + + + /** + * MIN + * + * MIN returns the value of the element of the values passed that has the smallest value, + * with negative numbers considered smaller than positive numbers. + * + * Excel Function: + * MIN(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function MIN() { + // Return value + $returnValue = null; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if ((is_null($returnValue)) || ($arg < $returnValue)) { + $returnValue = $arg; + } + } + } + + // Return + if(is_null($returnValue)) { + return 0; + } + return $returnValue; + } // function MIN() + + + /** + * MINA + * + * Returns the smallest value in a list of arguments, including numbers, text, and logical values + * + * Excel Function: + * MINA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function MINA() { + // Return value + $returnValue = null; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + if (is_bool($arg)) { + $arg = (integer) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + if ((is_null($returnValue)) || ($arg < $returnValue)) { + $returnValue = $arg; + } + } + } + + // Return + if(is_null($returnValue)) { + return 0; + } + return $returnValue; + } // function MINA() + + + /** + * MINIF + * + * Returns the minimum value within a range of cells that contain numbers within the list of arguments + * + * Excel Function: + * MINIF(value1[,value2[, ...]],condition) + * + * @access public + * @category Mathematical and Trigonometric Functions + * @param mixed $arg,... Data values + * @param string $condition The criteria that defines which cells will be checked. + * @return float + */ + public static function MINIF($aArgs,$condition,$sumArgs = array()) { + // Return value + $returnValue = null; + + $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs); + $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs); + if (count($sumArgs) == 0) { + $sumArgs = $aArgs; + } + $condition = PHPExcel_Calculation_Functions::_ifCondition($condition); + // Loop through arguments + foreach ($aArgs as $key => $arg) { + if (!is_numeric($arg)) { $arg = PHPExcel_Calculation::_wrapResult(strtoupper($arg)); } + $testCondition = '='.$arg.$condition; + if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) { + if ((is_null($returnValue)) || ($arg < $returnValue)) { + $returnValue = $arg; + } + } + } + + // Return + return $returnValue; + } // function MINIF() + + + // + // Special variant of array_count_values that isn't limited to strings and integers, + // but can work with floating point numbers as values + // + private static function _modeCalc($data) { + $frequencyArray = array(); + foreach($data as $datum) { + $found = False; + foreach($frequencyArray as $key => $value) { + if ((string) $value['value'] == (string) $datum) { + ++$frequencyArray[$key]['frequency']; + $found = True; + break; + } + } + if (!$found) { + $frequencyArray[] = array('value' => $datum, + 'frequency' => 1 ); + } + } + + foreach($frequencyArray as $key => $value) { + $frequencyList[$key] = $value['frequency']; + $valueList[$key] = $value['value']; + } + array_multisort($frequencyList, SORT_DESC, $valueList, SORT_ASC, SORT_NUMERIC, $frequencyArray); + + if ($frequencyArray[0]['frequency'] == 1) { + return PHPExcel_Calculation_Functions::NA(); + } + return $frequencyArray[0]['value']; + } // function _modeCalc() + + + /** + * MODE + * + * Returns the most frequently occurring, or repetitive, value in an array or range of data + * + * Excel Function: + * MODE(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function MODE() { + // Return value + $returnValue = PHPExcel_Calculation_Functions::NA(); + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + $mArgs = array(); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $mArgs[] = $arg; + } + } + + if (count($mArgs) > 0) { + return self::_modeCalc($mArgs); + } + + // Return + return $returnValue; + } // function MODE() + + + /** + * NEGBINOMDIST + * + * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that + * there will be number_f failures before the number_s-th success, when the constant + * probability of a success is probability_s. This function is similar to the binomial + * distribution, except that the number of successes is fixed, and the number of trials is + * variable. Like the binomial, trials are assumed to be independent. + * + * @param float $failures Number of Failures + * @param float $successes Threshold number of Successes + * @param float $probability Probability of success on each trial + * @return float + * + */ + public static function NEGBINOMDIST($failures, $successes, $probability) { + $failures = floor(PHPExcel_Calculation_Functions::flattenSingleValue($failures)); + $successes = floor(PHPExcel_Calculation_Functions::flattenSingleValue($successes)); + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + + if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) { + if (($failures < 0) || ($successes < 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (($probability < 0) || ($probability > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) { + if (($failures + $successes - 1) <= 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + } + return (PHPExcel_Calculation_MathTrig::COMBIN($failures + $successes - 1,$successes - 1)) * (pow($probability,$successes)) * (pow(1 - $probability,$failures)) ; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function NEGBINOMDIST() + + + /** + * NORMDIST + * + * Returns the normal distribution for the specified mean and standard deviation. This + * function has a very wide range of applications in statistics, including hypothesis + * testing. + * + * @param float $value + * @param float $mean Mean Value + * @param float $stdDev Standard Deviation + * @param boolean $cumulative + * @return float + * + */ + public static function NORMDIST($value, $mean, $stdDev, $cumulative) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean); + $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev); + + if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { + if ($stdDev < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ((is_numeric($cumulative)) || (is_bool($cumulative))) { + if ($cumulative) { + return 0.5 * (1 + PHPExcel_Calculation_Engineering::_erfVal(($value - $mean) / ($stdDev * sqrt(2)))); + } else { + return (1 / (SQRT2PI * $stdDev)) * exp(0 - (pow($value - $mean,2) / (2 * ($stdDev * $stdDev)))); + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function NORMDIST() + + + /** + * NORMINV + * + * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation. + * + * @param float $value + * @param float $mean Mean Value + * @param float $stdDev Standard Deviation + * @return float + * + */ + public static function NORMINV($probability,$mean,$stdDev) { + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean); + $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev); + + if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) { + if (($probability < 0) || ($probability > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ($stdDev < 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return (self::_inverse_ncdf($probability) * $stdDev) + $mean; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function NORMINV() + + + /** + * NORMSDIST + * + * Returns the standard normal cumulative distribution function. The distribution has + * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a + * table of standard normal curve areas. + * + * @param float $value + * @return float + */ + public static function NORMSDIST($value) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + + return self::NORMDIST($value, 0, 1, True); + } // function NORMSDIST() + + + /** + * NORMSINV + * + * Returns the inverse of the standard normal cumulative distribution + * + * @param float $value + * @return float + */ + public static function NORMSINV($value) { + return self::NORMINV($value, 0, 1); + } // function NORMSINV() + + + /** + * PERCENTILE + * + * Returns the nth percentile of values in a range.. + * + * Excel Function: + * PERCENTILE(value1[,value2[, ...]],entry) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @param float $entry Percentile value in the range 0..1, inclusive. + * @return float + */ + public static function PERCENTILE() { + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + // Calculate + $entry = array_pop($aArgs); + + if ((is_numeric($entry)) && (!is_string($entry))) { + if (($entry < 0) || ($entry > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $mArgs = array(); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $mArgs[] = $arg; + } + } + $mValueCount = count($mArgs); + if ($mValueCount > 0) { + sort($mArgs); + $count = self::COUNT($mArgs); + $index = $entry * ($count-1); + $iBase = floor($index); + if ($index == $iBase) { + return $mArgs[$index]; + } else { + $iNext = $iBase + 1; + $iProportion = $index - $iBase; + return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion) ; + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function PERCENTILE() + + + /** + * PERCENTRANK + * + * Returns the rank of a value in a data set as a percentage of the data set. + * + * @param array of number An array of, or a reference to, a list of numbers. + * @param number The number whose rank you want to find. + * @param number The number of significant digits for the returned percentage value. + * @return float + */ + public static function PERCENTRANK($valueSet,$value,$significance=3) { + $valueSet = PHPExcel_Calculation_Functions::flattenArray($valueSet); + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $significance = (is_null($significance)) ? 3 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($significance); + + foreach($valueSet as $key => $valueEntry) { + if (!is_numeric($valueEntry)) { + unset($valueSet[$key]); + } + } + sort($valueSet,SORT_NUMERIC); + $valueCount = count($valueSet); + if ($valueCount == 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + + $valueAdjustor = $valueCount - 1; + if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) { + return PHPExcel_Calculation_Functions::NA(); + } + + $pos = array_search($value,$valueSet); + if ($pos === False) { + $pos = 0; + $testValue = $valueSet[0]; + while ($testValue < $value) { + $testValue = $valueSet[++$pos]; + } + --$pos; + $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos])); + } + + return round($pos / $valueAdjustor,$significance); + } // function PERCENTRANK() + + + /** + * PERMUT + * + * Returns the number of permutations for a given number of objects that can be + * selected from number objects. A permutation is any set or subset of objects or + * events where internal order is significant. Permutations are different from + * combinations, for which the internal order is not significant. Use this function + * for lottery-style probability calculations. + * + * @param int $numObjs Number of different objects + * @param int $numInSet Number of objects in each permutation + * @return int Number of permutations + */ + public static function PERMUT($numObjs,$numInSet) { + $numObjs = PHPExcel_Calculation_Functions::flattenSingleValue($numObjs); + $numInSet = PHPExcel_Calculation_Functions::flattenSingleValue($numInSet); + + if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { + $numInSet = floor($numInSet); + if ($numObjs < $numInSet) { + return PHPExcel_Calculation_Functions::NaN(); + } + return round(PHPExcel_Calculation_MathTrig::FACT($numObjs) / PHPExcel_Calculation_MathTrig::FACT($numObjs - $numInSet)); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function PERMUT() + + + /** + * POISSON + * + * Returns the Poisson distribution. A common application of the Poisson distribution + * is predicting the number of events over a specific time, such as the number of + * cars arriving at a toll plaza in 1 minute. + * + * @param float $value + * @param float $mean Mean Value + * @param boolean $cumulative + * @return float + * + */ + public static function POISSON($value, $mean, $cumulative) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean); + + if ((is_numeric($value)) && (is_numeric($mean))) { + if (($value <= 0) || ($mean <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ((is_numeric($cumulative)) || (is_bool($cumulative))) { + if ($cumulative) { + $summer = 0; + for ($i = 0; $i <= floor($value); ++$i) { + $summer += pow($mean,$i) / PHPExcel_Calculation_MathTrig::FACT($i); + } + return exp(0-$mean) * $summer; + } else { + return (exp(0-$mean) * pow($mean,$value)) / PHPExcel_Calculation_MathTrig::FACT($value); + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function POISSON() + + + /** + * QUARTILE + * + * Returns the quartile of a data set. + * + * Excel Function: + * QUARTILE(value1[,value2[, ...]],entry) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @param int $entry Quartile value in the range 1..3, inclusive. + * @return float + */ + public static function QUARTILE() { + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + // Calculate + $entry = floor(array_pop($aArgs)); + + if ((is_numeric($entry)) && (!is_string($entry))) { + $entry /= 4; + if (($entry < 0) || ($entry > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + return self::PERCENTILE($aArgs,$entry); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function QUARTILE() + + + /** + * RANK + * + * Returns the rank of a number in a list of numbers. + * + * @param number The number whose rank you want to find. + * @param array of number An array of, or a reference to, a list of numbers. + * @param mixed Order to sort the values in the value set + * @return float + */ + public static function RANK($value,$valueSet,$order=0) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $valueSet = PHPExcel_Calculation_Functions::flattenArray($valueSet); + $order = (is_null($order)) ? 0 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($order); + + foreach($valueSet as $key => $valueEntry) { + if (!is_numeric($valueEntry)) { + unset($valueSet[$key]); + } + } + + if ($order == 0) { + rsort($valueSet,SORT_NUMERIC); + } else { + sort($valueSet,SORT_NUMERIC); + } + $pos = array_search($value,$valueSet); + if ($pos === False) { + return PHPExcel_Calculation_Functions::NA(); + } + + return ++$pos; + } // function RANK() + + + /** + * RSQ + * + * Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @return float + */ + public static function RSQ($yValues,$xValues) { + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); + return $bestFitLinear->getGoodnessOfFit(); + } // function RSQ() + + + /** + * SKEW + * + * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry + * of a distribution around its mean. Positive skewness indicates a distribution with an + * asymmetric tail extending toward more positive values. Negative skewness indicates a + * distribution with an asymmetric tail extending toward more negative values. + * + * @param array Data Series + * @return float + */ + public static function SKEW() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + $mean = self::AVERAGE($aArgs); + $stdDev = self::STDEV($aArgs); + + $count = $summer = 0; + // Loop through arguments + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + (!PHPExcel_Calculation_Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $summer += pow((($arg - $mean) / $stdDev),3) ; + ++$count; + } + } + } + + // Return + if ($count > 2) { + return $summer * ($count / (($count-1) * ($count-2))); + } + return PHPExcel_Calculation_Functions::DIV0(); + } // function SKEW() + + + /** + * SLOPE + * + * Returns the slope of the linear regression line through data points in known_y's and known_x's. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @return float + */ + public static function SLOPE($yValues,$xValues) { + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); + return $bestFitLinear->getSlope(); + } // function SLOPE() + + + /** + * SMALL + * + * Returns the nth smallest value in a data set. You can use this function to + * select a value based on its relative standing. + * + * Excel Function: + * SMALL(value1[,value2[, ...]],entry) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @param int $entry Position (ordered from the smallest) in the array or range of data to return + * @return float + */ + public static function SMALL() { + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + // Calculate + $entry = array_pop($aArgs); + + if ((is_numeric($entry)) && (!is_string($entry))) { + $mArgs = array(); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $mArgs[] = $arg; + } + } + $count = self::COUNT($mArgs); + $entry = floor(--$entry); + if (($entry < 0) || ($entry >= $count) || ($count == 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + sort($mArgs); + return $mArgs[$entry]; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SMALL() + + + /** + * STANDARDIZE + * + * Returns a normalized value from a distribution characterized by mean and standard_dev. + * + * @param float $value Value to normalize + * @param float $mean Mean Value + * @param float $stdDev Standard Deviation + * @return float Standardized value + */ + public static function STANDARDIZE($value,$mean,$stdDev) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean); + $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev); + + if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { + if ($stdDev <= 0) { + return PHPExcel_Calculation_Functions::NaN(); + } + return ($value - $mean) / $stdDev ; + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function STANDARDIZE() + + + /** + * STDEV + * + * Estimates standard deviation based on a sample. The standard deviation is a measure of how + * widely values are dispersed from the average value (the mean). + * + * Excel Function: + * STDEV(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function STDEV() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + + // Return value + $returnValue = null; + + $aMean = self::AVERAGE($aArgs); + if (!is_null($aMean)) { + $aCount = -1; + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) { + $arg = (integer) $arg; + } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if (is_null($returnValue)) { + $returnValue = pow(($arg - $aMean),2); + } else { + $returnValue += pow(($arg - $aMean),2); + } + ++$aCount; + } + } + + // Return + if (($aCount > 0) && ($returnValue >= 0)) { + return sqrt($returnValue / $aCount); + } + } + return PHPExcel_Calculation_Functions::DIV0(); + } // function STDEV() + + + /** + * STDEVA + * + * Estimates standard deviation based on a sample, including numbers, text, and logical values + * + * Excel Function: + * STDEVA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function STDEVA() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + + // Return value + $returnValue = null; + + $aMean = self::AVERAGEA($aArgs); + if (!is_null($aMean)) { + $aCount = -1; + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + (!PHPExcel_Calculation_Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { + if (is_bool($arg)) { + $arg = (integer) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + if (is_null($returnValue)) { + $returnValue = pow(($arg - $aMean),2); + } else { + $returnValue += pow(($arg - $aMean),2); + } + ++$aCount; + } + } + } + + // Return + if (($aCount > 0) && ($returnValue >= 0)) { + return sqrt($returnValue / $aCount); + } + } + return PHPExcel_Calculation_Functions::DIV0(); + } // function STDEVA() + + + /** + * STDEVP + * + * Calculates standard deviation based on the entire population + * + * Excel Function: + * STDEVP(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function STDEVP() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + + // Return value + $returnValue = null; + + $aMean = self::AVERAGE($aArgs); + if (!is_null($aMean)) { + $aCount = 0; + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) { + $arg = (integer) $arg; + } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + if (is_null($returnValue)) { + $returnValue = pow(($arg - $aMean),2); + } else { + $returnValue += pow(($arg - $aMean),2); + } + ++$aCount; + } + } + + // Return + if (($aCount > 0) && ($returnValue >= 0)) { + return sqrt($returnValue / $aCount); + } + } + return PHPExcel_Calculation_Functions::DIV0(); + } // function STDEVP() + + + /** + * STDEVPA + * + * Calculates standard deviation based on the entire population, including numbers, text, and logical values + * + * Excel Function: + * STDEVPA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function STDEVPA() { + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + + // Return value + $returnValue = null; + + $aMean = self::AVERAGEA($aArgs); + if (!is_null($aMean)) { + $aCount = 0; + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && + (!PHPExcel_Calculation_Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { + if (is_bool($arg)) { + $arg = (integer) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + if (is_null($returnValue)) { + $returnValue = pow(($arg - $aMean),2); + } else { + $returnValue += pow(($arg - $aMean),2); + } + ++$aCount; + } + } + } + + // Return + if (($aCount > 0) && ($returnValue >= 0)) { + return sqrt($returnValue / $aCount); + } + } + return PHPExcel_Calculation_Functions::DIV0(); + } // function STDEVPA() + + + /** + * STEYX + * + * Returns the standard error of the predicted y-value for each x in the regression. + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @return float + */ + public static function STEYX($yValues,$xValues) { + if (!self::_checkTrendArrays($yValues,$xValues)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { + return PHPExcel_Calculation_Functions::NA(); + } elseif ($yValueCount == 1) { + return PHPExcel_Calculation_Functions::DIV0(); + } + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues); + return $bestFitLinear->getStdevOfResiduals(); + } // function STEYX() + + + /** + * TDIST + * + * Returns the probability of Student's T distribution. + * + * @param float $value Value for the function + * @param float $degrees degrees of freedom + * @param float $tails number of tails (1 or 2) + * @return float + */ + public static function TDIST($value, $degrees, $tails) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees)); + $tails = floor(PHPExcel_Calculation_Functions::flattenSingleValue($tails)); + + if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) { + if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) { + return PHPExcel_Calculation_Functions::NaN(); + } + // tdist, which finds the probability that corresponds to a given value + // of t with k degrees of freedom. This algorithm is translated from a + // pascal function on p81 of "Statistical Computing in Pascal" by D + // Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd: + // London). The above Pascal algorithm is itself a translation of the + // fortran algoritm "AS 3" by B E Cooper of the Atlas Computer + // Laboratory as reported in (among other places) "Applied Statistics + // Algorithms", editied by P Griffiths and I D Hill (1985; Ellis + // Horwood Ltd.; W. Sussex, England). + $tterm = $degrees; + $ttheta = atan2($value,sqrt($tterm)); + $tc = cos($ttheta); + $ts = sin($ttheta); + $tsum = 0; + + if (($degrees % 2) == 1) { + $ti = 3; + $tterm = $tc; + } else { + $ti = 2; + $tterm = 1; + } + + $tsum = $tterm; + while ($ti < $degrees) { + $tterm *= $tc * $tc * ($ti - 1) / $ti; + $tsum += $tterm; + $ti += 2; + } + $tsum *= $ts; + if (($degrees % 2) == 1) { $tsum = M_2DIVPI * ($tsum + $ttheta); } + $tValue = 0.5 * (1 + $tsum); + if ($tails == 1) { + return 1 - abs($tValue); + } else { + return 1 - abs((1 - $tValue) - $tValue); + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function TDIST() + + + /** + * TINV + * + * Returns the one-tailed probability of the chi-squared distribution. + * + * @param float $probability Probability for the function + * @param float $degrees degrees of freedom + * @return float + */ + public static function TINV($probability, $degrees) { + $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); + $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees)); + + if ((is_numeric($probability)) && (is_numeric($degrees))) { + $xLo = 100; + $xHi = 0; + + $x = $xNew = 1; + $dx = 1; + $i = 0; + + while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { + // Apply Newton-Raphson step + $result = self::TDIST($x, $degrees, 2); + $error = $result - $probability; + if ($error == 0.0) { + $dx = 0; + } elseif ($error < 0.0) { + $xLo = $x; + } else { + $xHi = $x; + } + // Avoid division by zero + if ($result != 0.0) { + $dx = $error / $result; + $xNew = $x - $dx; + } + // If the NR fails to converge (which for example may be the + // case if the initial guess is too rough) we apply a bisection + // step to determine a more narrow interval around the root. + if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { + $xNew = ($xLo + $xHi) / 2; + $dx = $xNew - $x; + } + $x = $xNew; + } + if ($i == MAX_ITERATIONS) { + return PHPExcel_Calculation_Functions::NA(); + } + return round($x,12); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function TINV() + + + /** + * TREND + * + * Returns values along a linear trend + * + * @param array of mixed Data Series Y + * @param array of mixed Data Series X + * @param array of mixed Values of X for which we want to find Y + * @param boolean A logical value specifying whether to force the intersect to equal 0. + * @return array of float + */ + public static function TREND($yValues,$xValues=array(),$newValues=array(),$const=True) { + $yValues = PHPExcel_Calculation_Functions::flattenArray($yValues); + $xValues = PHPExcel_Calculation_Functions::flattenArray($xValues); + $newValues = PHPExcel_Calculation_Functions::flattenArray($newValues); + $const = (is_null($const)) ? True : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const); + + $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR,$yValues,$xValues,$const); + if (count($newValues) == 0) { + $newValues = $bestFitLinear->getXValues(); + } + + $returnArray = array(); + foreach($newValues as $xValue) { + $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue); + } + + return $returnArray; + } // function TREND() + + + /** + * TRIMMEAN + * + * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean + * taken by excluding a percentage of data points from the top and bottom tails + * of a data set. + * + * Excel Function: + * TRIMEAN(value1[,value2[, ...]],$discard) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @param float $discard Percentage to discard + * @return float + */ + public static function TRIMMEAN() { + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + + // Calculate + $percent = array_pop($aArgs); + + if ((is_numeric($percent)) && (!is_string($percent))) { + if (($percent < 0) || ($percent > 1)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $mArgs = array(); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $mArgs[] = $arg; + } + } + $discard = floor(self::COUNT($mArgs) * $percent / 2); + sort($mArgs); + for ($i=0; $i < $discard; ++$i) { + array_pop($mArgs); + array_shift($mArgs); + } + return self::AVERAGE($mArgs); + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function TRIMMEAN() + + + /** + * VARFunc + * + * Estimates variance based on a sample. + * + * Excel Function: + * VAR(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function VARFunc() { + // Return value + $returnValue = PHPExcel_Calculation_Functions::DIV0(); + + $summerA = $summerB = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + $aCount = 0; + foreach ($aArgs as $arg) { + if (is_bool($arg)) { $arg = (integer) $arg; } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $summerA += ($arg * $arg); + $summerB += $arg; + ++$aCount; + } + } + + // Return + if ($aCount > 1) { + $summerA *= $aCount; + $summerB *= $summerB; + $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1)); + } + return $returnValue; + } // function VARFunc() + + + /** + * VARA + * + * Estimates variance based on a sample, including numbers, text, and logical values + * + * Excel Function: + * VARA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function VARA() { + // Return value + $returnValue = PHPExcel_Calculation_Functions::DIV0(); + + $summerA = $summerB = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + $aCount = 0; + foreach ($aArgs as $k => $arg) { + if ((is_string($arg)) && + (PHPExcel_Calculation_Functions::isValue($k))) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ((is_string($arg)) && + (!PHPExcel_Calculation_Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { + if (is_bool($arg)) { + $arg = (integer) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + $summerA += ($arg * $arg); + $summerB += $arg; + ++$aCount; + } + } + } + + // Return + if ($aCount > 1) { + $summerA *= $aCount; + $summerB *= $summerB; + $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1)); + } + return $returnValue; + } // function VARA() + + + /** + * VARP + * + * Calculates variance based on the entire population + * + * Excel Function: + * VARP(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function VARP() { + // Return value + $returnValue = PHPExcel_Calculation_Functions::DIV0(); + + $summerA = $summerB = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + $aCount = 0; + foreach ($aArgs as $arg) { + if (is_bool($arg)) { $arg = (integer) $arg; } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $summerA += ($arg * $arg); + $summerB += $arg; + ++$aCount; + } + } + + // Return + if ($aCount > 0) { + $summerA *= $aCount; + $summerB *= $summerB; + $returnValue = ($summerA - $summerB) / ($aCount * $aCount); + } + return $returnValue; + } // function VARP() + + + /** + * VARPA + * + * Calculates variance based on the entire population, including numbers, text, and logical values + * + * Excel Function: + * VARPA(value1[,value2[, ...]]) + * + * @access public + * @category Statistical Functions + * @param mixed $arg,... Data values + * @return float + */ + public static function VARPA() { + // Return value + $returnValue = PHPExcel_Calculation_Functions::DIV0(); + + $summerA = $summerB = 0; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()); + $aCount = 0; + foreach ($aArgs as $k => $arg) { + if ((is_string($arg)) && + (PHPExcel_Calculation_Functions::isValue($k))) { + return PHPExcel_Calculation_Functions::VALUE(); + } elseif ((is_string($arg)) && + (!PHPExcel_Calculation_Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { + if (is_bool($arg)) { + $arg = (integer) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + $summerA += ($arg * $arg); + $summerB += $arg; + ++$aCount; + } + } + } + + // Return + if ($aCount > 0) { + $summerA *= $aCount; + $summerB *= $summerB; + $returnValue = ($summerA - $summerB) / ($aCount * $aCount); + } + return $returnValue; + } // function VARPA() + + + /** + * WEIBULL + * + * Returns the Weibull distribution. Use this distribution in reliability + * analysis, such as calculating a device's mean time to failure. + * + * @param float $value + * @param float $alpha Alpha Parameter + * @param float $beta Beta Parameter + * @param boolean $cumulative + * @return float + * + */ + public static function WEIBULL($value, $alpha, $beta, $cumulative) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha); + $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta); + + if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) { + if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) { + return PHPExcel_Calculation_Functions::NaN(); + } + if ((is_numeric($cumulative)) || (is_bool($cumulative))) { + if ($cumulative) { + return 1 - exp(0 - pow($value / $beta,$alpha)); + } else { + return ($alpha / pow($beta,$alpha)) * pow($value,$alpha - 1) * exp(0 - pow($value / $beta,$alpha)); + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function WEIBULL() + + + /** + * ZTEST + * + * Returns the Weibull distribution. Use this distribution in reliability + * analysis, such as calculating a device's mean time to failure. + * + * @param float $value + * @param float $alpha Alpha Parameter + * @param float $beta Beta Parameter + * @param boolean $cumulative + * @return float + * + */ + public static function ZTEST($dataSet, $m0, $sigma=null) { + $dataSet = PHPExcel_Calculation_Functions::flattenArrayIndexed($dataSet); + $m0 = PHPExcel_Calculation_Functions::flattenSingleValue($m0); + $sigma = PHPExcel_Calculation_Functions::flattenSingleValue($sigma); + + if (is_null($sigma)) { + $sigma = self::STDEV($dataSet); + } + $n = count($dataSet); + + return 1 - self::NORMSDIST((self::AVERAGE($dataSet) - $m0)/($sigma/SQRT($n))); + } // function ZTEST() + +} // class PHPExcel_Calculation_Statistical diff --git a/libraries/PHPExcel/PHPExcel/Calculation/TextData.php b/libraries/PHPExcel/PHPExcel/Calculation/TextData.php new file mode 100644 index 000000000..991687625 --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Calculation/TextData.php @@ -0,0 +1,588 @@ +=0 && ord($c{0}) <= 127) + return ord($c{0}); + if (ord($c{0}) >= 192 && ord($c{0}) <= 223) + return (ord($c{0})-192)*64 + (ord($c{1})-128); + if (ord($c{0}) >= 224 && ord($c{0}) <= 239) + return (ord($c{0})-224)*4096 + (ord($c{1})-128)*64 + (ord($c{2})-128); + if (ord($c{0}) >= 240 && ord($c{0}) <= 247) + return (ord($c{0})-240)*262144 + (ord($c{1})-128)*4096 + (ord($c{2})-128)*64 + (ord($c{3})-128); + if (ord($c{0}) >= 248 && ord($c{0}) <= 251) + return (ord($c{0})-248)*16777216 + (ord($c{1})-128)*262144 + (ord($c{2})-128)*4096 + (ord($c{3})-128)*64 + (ord($c{4})-128); + if (ord($c{0}) >= 252 && ord($c{0}) <= 253) + return (ord($c{0})-252)*1073741824 + (ord($c{1})-128)*16777216 + (ord($c{2})-128)*262144 + (ord($c{3})-128)*4096 + (ord($c{4})-128)*64 + (ord($c{5})-128); + if (ord($c{0}) >= 254 && ord($c{0}) <= 255) //error + return PHPExcel_Calculation_Functions::VALUE(); + return 0; + } // function _uniord() + + /** + * CHARACTER + * + * @param string $character Value + * @return int + */ + public static function CHARACTER($character) { + $character = PHPExcel_Calculation_Functions::flattenSingleValue($character); + + if ((!is_numeric($character)) || ($character < 0)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding('&#'.intval($character).';', 'UTF-8', 'HTML-ENTITIES'); + } else { + return chr(intval($character)); + } + } + + + /** + * TRIMNONPRINTABLE + * + * @param mixed $value Value to check + * @return string + */ + public static function TRIMNONPRINTABLE($stringValue = '') { + $stringValue = PHPExcel_Calculation_Functions::flattenSingleValue($stringValue); + + if (is_bool($stringValue)) { + $stringValue = ($stringValue) ? 'TRUE' : 'FALSE'; + } + + if (self::$_invalidChars == Null) { + self::$_invalidChars = range(chr(0),chr(31)); + } + + if (is_string($stringValue) || is_numeric($stringValue)) { + return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F")); + } + return Null; + } // function TRIMNONPRINTABLE() + + + /** + * TRIMSPACES + * + * @param mixed $value Value to check + * @return string + */ + public static function TRIMSPACES($stringValue = '') { + $stringValue = PHPExcel_Calculation_Functions::flattenSingleValue($stringValue); + + if (is_string($stringValue) || is_numeric($stringValue)) { + return trim(preg_replace('/ +/',' ',$stringValue)); + } + return Null; + } // function TRIMSPACES() + + + /** + * ASCIICODE + * + * @param string $character Value + * @return int + */ + public static function ASCIICODE($characters) { + $characters = PHPExcel_Calculation_Functions::flattenSingleValue($characters); + if (is_bool($characters)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $characters = (int) $characters; + } else { + if ($characters) { + $characters = 'True'; + } else { + $characters = 'False'; + } + } + } + + $character = $characters; + if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) { + if (mb_strlen($characters, 'UTF-8') > 1) { $character = mb_substr($characters, 0, 1, 'UTF-8'); } + return self::_uniord($character); + } else { + if (strlen($characters) > 0) { $character = substr($characters, 0, 1); } + return ord($character); + } + } // function ASCIICODE() + + + /** + * CONCATENATE + * + * @return string + */ + public static function CONCATENATE() { + // Return value + $returnValue = ''; + + // Loop through arguments + $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); + foreach ($aArgs as $arg) { + if (is_bool($arg)) { + if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) { + $arg = (int) $arg; + } else { + if ($arg) { + $arg = 'TRUE'; + } else { + $arg = 'FALSE'; + } + } + } + $returnValue .= $arg; + } + + // Return + return $returnValue; + } // function CONCATENATE() + + + /** + * DOLLAR + * + * This function converts a number to text using currency format, with the decimals rounded to the specified place. + * The format used is $#,##0.00_);($#,##0.00).. + * + * @param float $value The value to format + * @param int $decimals The number of digits to display to the right of the decimal point. + * If decimals is negative, number is rounded to the left of the decimal point. + * If you omit decimals, it is assumed to be 2 + * @return string + */ + public static function DOLLAR($value = 0, $decimals = 2) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $decimals = is_null($decimals) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($decimals); + + // Validate parameters + if (!is_numeric($value) || !is_numeric($decimals)) { + return PHPExcel_Calculation_Functions::NaN(); + } + $decimals = floor($decimals); + + if ($decimals > 0) { + return money_format('%.'.$decimals.'n',$value); + } else { + $round = pow(10,abs($decimals)); + if ($value < 0) { $round = 0-$round; } + $value = PHPExcel_Calculation_MathTrig::MROUND($value,$round); + // The implementation of money_format used if the standard PHP function is not available can't handle decimal places of 0, + // so we display to 1 dp and chop off that character and the decimal separator using substr + return substr(money_format('%.1n',$value),0,-2); + } + } // function DOLLAR() + + + /** + * SEARCHSENSITIVE + * + * @param string $needle The string to look for + * @param string $haystack The string in which to look + * @param int $offset Offset within $haystack + * @return string + */ + public static function SEARCHSENSITIVE($needle,$haystack,$offset=1) { + $needle = PHPExcel_Calculation_Functions::flattenSingleValue($needle); + $haystack = PHPExcel_Calculation_Functions::flattenSingleValue($haystack); + $offset = PHPExcel_Calculation_Functions::flattenSingleValue($offset); + + if (!is_bool($needle)) { + if (is_bool($haystack)) { + $haystack = ($haystack) ? 'TRUE' : 'FALSE'; + } + + if (($offset > 0) && (strlen($haystack) > $offset)) { + if (function_exists('mb_strpos')) { + $pos = mb_strpos($haystack, $needle, --$offset,'UTF-8'); + } else { + $pos = strpos($haystack, $needle, --$offset); + } + if ($pos !== false) { + return ++$pos; + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SEARCHSENSITIVE() + + + /** + * SEARCHINSENSITIVE + * + * @param string $needle The string to look for + * @param string $haystack The string in which to look + * @param int $offset Offset within $haystack + * @return string + */ + public static function SEARCHINSENSITIVE($needle,$haystack,$offset=1) { + $needle = PHPExcel_Calculation_Functions::flattenSingleValue($needle); + $haystack = PHPExcel_Calculation_Functions::flattenSingleValue($haystack); + $offset = PHPExcel_Calculation_Functions::flattenSingleValue($offset); + + if (!is_bool($needle)) { + if (is_bool($haystack)) { + $haystack = ($haystack) ? 'TRUE' : 'FALSE'; + } + + if (($offset > 0) && (strlen($haystack) > $offset)) { + if (function_exists('mb_stripos')) { + $pos = mb_stripos($haystack, $needle, --$offset,'UTF-8'); + } else { + $pos = stripos($haystack, $needle, --$offset); + } + if ($pos !== false) { + return ++$pos; + } + } + } + return PHPExcel_Calculation_Functions::VALUE(); + } // function SEARCHINSENSITIVE() + + + /** + * FIXEDFORMAT + * + * @param mixed $value Value to check + * @return boolean + */ + public static function FIXEDFORMAT($value,$decimals=2,$no_commas=false) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $decimals = PHPExcel_Calculation_Functions::flattenSingleValue($decimals); + $no_commas = PHPExcel_Calculation_Functions::flattenSingleValue($no_commas); + + $valueResult = round($value,$decimals); + if ($decimals < 0) { $decimals = 0; } + if (!$no_commas) { + $valueResult = number_format($valueResult,$decimals); + } + + return (string) $valueResult; + } // function FIXEDFORMAT() + + + /** + * LEFT + * + * @param string $value Value + * @param int $chars Number of characters + * @return string + */ + public static function LEFT($value = '', $chars = 1) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars); + + if ($chars < 0) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (is_bool($value)) { + $value = ($value) ? 'TRUE' : 'FALSE'; + } + + if (function_exists('mb_substr')) { + return mb_substr($value, 0, $chars, 'UTF-8'); + } else { + return substr($value, 0, $chars); + } + } // function LEFT() + + + /** + * MID + * + * @param string $value Value + * @param int $start Start character + * @param int $chars Number of characters + * @return string + */ + public static function MID($value = '', $start = 1, $chars = null) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $start = PHPExcel_Calculation_Functions::flattenSingleValue($start); + $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars); + + if (($start < 1) || ($chars < 0)) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (is_bool($value)) { + $value = ($value) ? 'TRUE' : 'FALSE'; + } + + if (function_exists('mb_substr')) { + return mb_substr($value, --$start, $chars, 'UTF-8'); + } else { + return substr($value, --$start, $chars); + } + } // function MID() + + + /** + * RIGHT + * + * @param string $value Value + * @param int $chars Number of characters + * @return string + */ + public static function RIGHT($value = '', $chars = 1) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars); + + if ($chars < 0) { + return PHPExcel_Calculation_Functions::VALUE(); + } + + if (is_bool($value)) { + $value = ($value) ? 'TRUE' : 'FALSE'; + } + + if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) { + return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8'); + } else { + return substr($value, strlen($value) - $chars); + } + } // function RIGHT() + + + /** + * STRINGLENGTH + * + * @param string $value Value + * @param int $chars Number of characters + * @return string + */ + public static function STRINGLENGTH($value = '') { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + + if (is_bool($value)) { + $value = ($value) ? 'TRUE' : 'FALSE'; + } + + if (function_exists('mb_strlen')) { + return mb_strlen($value, 'UTF-8'); + } else { + return strlen($value); + } + } // function STRINGLENGTH() + + + /** + * LOWERCASE + * + * Converts a string value to upper case. + * + * @param string $mixedCaseString + * @return string + */ + public static function LOWERCASE($mixedCaseString) { + $mixedCaseString = PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString); + + if (is_bool($mixedCaseString)) { + $mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE'; + } + + if (function_exists('mb_convert_case')) { + return mb_convert_case($mixedCaseString, MB_CASE_LOWER, 'UTF-8'); + } else { + return strtoupper($mixedCaseString); + } + } // function LOWERCASE() + + + /** + * UPPERCASE + * + * Converts a string value to upper case. + * + * @param string $mixedCaseString + * @return string + */ + public static function UPPERCASE($mixedCaseString) { + $mixedCaseString = PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString); + + if (is_bool($mixedCaseString)) { + $mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE'; + } + + if (function_exists('mb_convert_case')) { + return mb_convert_case($mixedCaseString, MB_CASE_UPPER, 'UTF-8'); + } else { + return strtoupper($mixedCaseString); + } + } // function UPPERCASE() + + + /** + * PROPERCASE + * + * Converts a string value to upper case. + * + * @param string $mixedCaseString + * @return string + */ + public static function PROPERCASE($mixedCaseString) { + $mixedCaseString = PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString); + + if (is_bool($mixedCaseString)) { + $mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE'; + } + + if (function_exists('mb_convert_case')) { + return mb_convert_case($mixedCaseString, MB_CASE_TITLE, 'UTF-8'); + } else { + return ucwords($mixedCaseString); + } + } // function PROPERCASE() + + + /** + * REPLACE + * + * @param string $value Value + * @param int $start Start character + * @param int $chars Number of characters + * @return string + */ + public static function REPLACE($oldText = '', $start = 1, $chars = null, $newText) { + $oldText = PHPExcel_Calculation_Functions::flattenSingleValue($oldText); + $start = PHPExcel_Calculation_Functions::flattenSingleValue($start); + $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars); + $newText = PHPExcel_Calculation_Functions::flattenSingleValue($newText); + + $left = self::LEFT($oldText,$start-1); + $right = self::RIGHT($oldText,self::STRINGLENGTH($oldText)-($start+$chars)+1); + + return $left.$newText.$right; + } // function REPLACE() + + + /** + * SUBSTITUTE + * + * @param string $text Value + * @param string $fromText From Value + * @param string $toText To Value + * @param integer $instance Instance Number + * @return string + */ + public static function SUBSTITUTE($text = '', $fromText = '', $toText = '', $instance = 0) { + $text = PHPExcel_Calculation_Functions::flattenSingleValue($text); + $fromText = PHPExcel_Calculation_Functions::flattenSingleValue($fromText); + $toText = PHPExcel_Calculation_Functions::flattenSingleValue($toText); + $instance = floor(PHPExcel_Calculation_Functions::flattenSingleValue($instance)); + + if ($instance == 0) { + if(function_exists('mb_str_replace')) { + return mb_str_replace($fromText,$toText,$text); + } else { + return str_replace($fromText,$toText,$text); + } + } else { + $pos = -1; + while($instance > 0) { + if (function_exists('mb_strpos')) { + $pos = mb_strpos($text, $fromText, $pos+1, 'UTF-8'); + } else { + $pos = strpos($text, $fromText, $pos+1); + } + if ($pos === false) { + break; + } + --$instance; + } + if ($pos !== false) { + if (function_exists('mb_strlen')) { + return self::REPLACE($text,++$pos,mb_strlen($fromText, 'UTF-8'),$toText); + } else { + return self::REPLACE($text,++$pos,strlen($fromText),$toText); + } + } + } + + return $left.$newText.$right; + } // function SUBSTITUTE() + + + /** + * RETURNSTRING + * + * @param mixed $value Value to check + * @return boolean + */ + public static function RETURNSTRING($testValue = '') { + $testValue = PHPExcel_Calculation_Functions::flattenSingleValue($testValue); + + if (is_string($testValue)) { + return $testValue; + } + return Null; + } // function RETURNSTRING() + + + /** + * TEXTFORMAT + * + * @param mixed $value Value to check + * @return boolean + */ + public static function TEXTFORMAT($value,$format) { + $value = PHPExcel_Calculation_Functions::flattenSingleValue($value); + $format = PHPExcel_Calculation_Functions::flattenSingleValue($format); + + if ((is_string($value)) && (!is_numeric($value)) && PHPExcel_Shared_Date::isDateTimeFormatCode($format)) { + $value = PHPExcel_Calculation_DateTime::DATEVALUE($value); + } + + return (string) PHPExcel_Style_NumberFormat::toFormattedString($value,$format); + } // function TEXTFORMAT() + +} // class PHPExcel_Calculation_TextData diff --git a/libraries/PHPExcel/PHPExcel/Cell.php b/libraries/PHPExcel/PHPExcel/Cell.php index b805b8df2..996d68aa7 100644 --- a/libraries/PHPExcel/PHPExcel/Cell.php +++ b/libraries/PHPExcel/PHPExcel/Cell.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Cell { @@ -140,7 +140,9 @@ class PHPExcel_Cell $this->_parent = $pSheet; // Set datatype? - if (!is_null($pDataType)) { + if ($pDataType !== null) { + if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2) + $pDataType = PHPExcel_Cell_DataType::TYPE_STRING; $this->_dataType = $pDataType; } else { if (!self::getValueBinder()->bindValue($this, $pValue)) { @@ -192,6 +194,18 @@ class PHPExcel_Cell return $this->_value; } + /** + * Get cell value with formatting + * + * @return string + */ + public function getFormattedValue() + { + return PHPExcel_Style_NumberFormat::toFormattedString( $this->getCalculatedValue(), + $this->_parent->getParent()->getCellXfByIndex($this->getXfIndex())->getNumberFormat()->getFormatCode() + ); + } + /** * Set cell value * @@ -220,6 +234,8 @@ class PHPExcel_Cell { // set the value according to data type switch ($pDataType) { + case PHPExcel_Cell_DataType::TYPE_STRING2: + $pDataType = PHPExcel_Cell_DataType::TYPE_STRING; case PHPExcel_Cell_DataType::TYPE_STRING: case PHPExcel_Cell_DataType::TYPE_NULL: case PHPExcel_Cell_DataType::TYPE_INLINE: @@ -280,10 +296,10 @@ class PHPExcel_Cell return $result; } - if (is_null($this->_value)) { +// if (is_null($this->_value)) { // echo 'Cell '.$this->getCoordinate().' has no value, formula or otherwise
'; - return null; - } +// return null; +// } // echo 'Cell value for '.$this->getCoordinate().' is not a formula: Returning data value of '.$this->_value.'
'; return $this->_value; } @@ -331,6 +347,9 @@ class PHPExcel_Cell */ public function setDataType($pDataType = PHPExcel_Cell_DataType::TYPE_STRING) { + if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2) + $pDataType = PHPExcel_Cell_DataType::TYPE_STRING; + $this->_dataType = $pDataType; return $this->notifyCacheController(); @@ -461,7 +480,7 @@ class PHPExcel_Cell list($rangeStart,$rangeEnd) = PHPExcel_Cell::rangeBoundaries($pRange); // Translate properties - $myColumn = PHPExcel_Cell::columnIndexFromString($this->getColumn()) - 1; + $myColumn = PHPExcel_Cell::columnIndexFromString($this->getColumn()); $myRow = $this->getRow(); // Verify if cell is in range @@ -479,23 +498,44 @@ class PHPExcel_Cell */ public static function coordinateFromString($pCoordinateString = 'A1') { - if (strpos($pCoordinateString,':') !== false) { + if (preg_match("/^([$]?[A-Z]{1,3})([$]?\d{1,7})$/", $pCoordinateString, $matches)) { + return array($matches[1],$matches[2]); + } elseif ((strpos($pCoordinateString,':') !== false) || (strpos($pCoordinateString,',') !== false)) { throw new Exception('Cell coordinate string can not be a range of cells.'); - } else if ($pCoordinateString == '') { + } elseif ($pCoordinateString == '') { throw new Exception('Cell coordinate can not be zero-length string.'); - } else if (preg_match("/([$]?[A-Z]+)([$]?\d+)/", $pCoordinateString, $matches)) { - list(, $column, $row) = $matches; - return array($column, $row); } else { - throw new Exception('Invalid cell coordinate.'); + throw new Exception('Invalid cell coordinate '.$pCoordinateString); + } + } + + /** + * Make string row, column or cell coordinate absolute + * + * @param string $pCoordinateString e.g. 'A' or '1' or 'A1' + * @return string Absolute coordinate e.g. '$A' or '$1' or '$A$1' + * @throws Exception + */ + public static function absoluteReference($pCoordinateString = 'A1') + { + if (strpos($pCoordinateString,':') === false && strpos($pCoordinateString,',') === false) { + // Create absolute coordinate + if (ctype_digit($pCoordinateString)) { + return '$'.$pCoordinateString; + } elseif (ctype_alpha($pCoordinateString)) { + return '$'.strtoupper($pCoordinateString); + } + return self::absoluteCoordinate($pCoordinateString); + } else { + throw new Exception("Coordinate string should not be a cell range."); } } /** * Make string coordinate absolute * - * @param string $pCoordinateString - * @return string Absolute coordinate + * @param string $pCoordinateString e.g. 'A1' + * @return string Absolute coordinate e.g. '$A$1' * @throws Exception */ public static function absoluteCoordinate($pCoordinateString = 'A1') @@ -503,6 +543,8 @@ class PHPExcel_Cell if (strpos($pCoordinateString,':') === false && strpos($pCoordinateString,',') === false) { // Create absolute coordinate list($column, $row) = PHPExcel_Cell::coordinateFromString($pCoordinateString); + if ($column[0] == '$') $column = substr($column,1); + if ($row[0] == '$') $row = substr($row,1); return '$' . $column . '$' . $row; } else { throw new Exception("Coordinate string should not be a cell range."); @@ -518,7 +560,8 @@ class PHPExcel_Cell public static function splitRange($pRange = 'A1:A1') { $exploded = explode(',', $pRange); - for ($i = 0; $i < count($exploded); ++$i) { + $counter = count($exploded); + for ($i = 0; $i < $counter; ++$i) { $exploded[$i] = explode(':', $exploded[$i]); } return $exploded; @@ -540,7 +583,8 @@ class PHPExcel_Cell // Build range $imploded = array(); - for ($i = 0; $i < count($pRange); ++$i) { + $counter = count($pRange); + for ($i = 0; $i < $counter; ++$i) { $pRange[$i] = implode(':', $pRange[$i]); } $imploded = implode(',', $pRange); @@ -604,8 +648,7 @@ class PHPExcel_Cell // Extract range if (strpos($pRange, ':') === false) { - $rangeA = $pRange; - $rangeB = $pRange; + $rangeA = $rangeB = $pRange; } else { list($rangeA, $rangeB) = explode(':', $pRange); } @@ -622,28 +665,28 @@ class PHPExcel_Cell */ public static function columnIndexFromString($pString = 'A') { - static $lookup = array( + // It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array rather than use ord() + // and make it case insensitive to get rid of the strtoupper() as well. Because it's a static, there's no significant + // memory overhead either + static $_columnLookup = 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 + '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, + '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 ); - if (isset($lookup[$pString])) - return $lookup[$pString]; - - // Convert to uppercase - $pString = strtoupper($pString); - - $strLen = strlen($pString); - // Convert column to integer - if ($strLen == 1) { - return (ord($pString{0}) - 64); - } elseif ($strLen == 2) { - return $result = ((1 + (ord($pString{0}) - 65)) * 26) + (ord($pString{1}) - 64); - } elseif ($strLen == 3) { - return ((1 + (ord($pString{0}) - 65)) * 676) + ((1 + (ord($pString{1}) - 65)) * 26) + (ord($pString{2}) - 64); - } else { - throw new Exception("Column string index can not be " . ($strLen != 0 ? "longer than 3 characters" : "empty") . "."); + // We also use the language construct isset() rather than the more costly strlen() function to match the length of $pString + // for improved performance + if (isset($pString{0})) { + if (!isset($pString{1})) { + return $_columnLookup[$pString]; + } elseif(!isset($pString{2})) { + return $_columnLookup[$pString{0}] * 26 + $_columnLookup[$pString{1}]; + } elseif(!isset($pString{3})) { + return $_columnLookup[$pString{0}] * 676 + $_columnLookup[$pString{1}] * 26 + $_columnLookup[$pString{2}]; + } } + throw new Exception("Column string index can not be " . ((isset($pString{0})) ? "longer than 3 characters" : "empty") . "."); } /** @@ -657,8 +700,10 @@ class PHPExcel_Cell // Determine column string if ($pColumnIndex < 26) { return chr(65 + $pColumnIndex); + } elseif ($pColumnIndex < 702) { + return chr(64 + ($pColumnIndex / 26)).chr(65 + $pColumnIndex % 26); } - return PHPExcel_Cell::stringFromColumnIndex((int)($pColumnIndex / 26) -1).chr(65 + $pColumnIndex%26) ; + return chr(64 + (($pColumnIndex - 26) / 676)).chr(65 + ((($pColumnIndex - 26) % 676) / 26)).chr(65 + $pColumnIndex % 26); } /** @@ -672,60 +717,41 @@ class PHPExcel_Cell $returnValue = array(); // Explode spaces - $aExplodeSpaces = explode(' ', str_replace('$', '', strtoupper($pRange))); - foreach ($aExplodeSpaces as $explodedSpaces) { + $cellBlocks = explode(' ', str_replace('$', '', strtoupper($pRange))); + foreach ($cellBlocks as $cellBlock) { // Single cell? - if (strpos($explodedSpaces,':') === false && strpos($explodedSpaces,',') === false) { - $col = 'A'; - $row = 1; - list($col, $row) = PHPExcel_Cell::coordinateFromString($explodedSpaces); - - if (strlen($col) <= 2) { - $returnValue[] = $explodedSpaces; - } - + if (strpos($cellBlock,':') === false && strpos($cellBlock,',') === false) { + $returnValue[] = $cellBlock; continue; } // Range... - $range = PHPExcel_Cell::splitRange($explodedSpaces); - for ($i = 0; $i < count($range); ++$i) { + $ranges = PHPExcel_Cell::splitRange($cellBlock); + foreach($ranges as $range) { // Single cell? - if (count($range[$i]) == 1) { - $col = 'A'; - $row = 1; - list($col, $row) = PHPExcel_Cell::coordinateFromString($range[$i]); - - if (strlen($col) <= 2) { - $returnValue[] = $explodedSpaces; - } + if (!isset($range[1])) { + $returnValue[] = $range[0]; + continue; } // Range... - $rangeStart = $rangeEnd = ''; - $startingCol = $startingRow = $endingCol = $endingRow = 0; - - list($rangeStart, $rangeEnd) = $range[$i]; - list($startingCol, $startingRow) = PHPExcel_Cell::coordinateFromString($rangeStart); - list($endingCol, $endingRow) = PHPExcel_Cell::coordinateFromString($rangeEnd); - - // Conversions... - $startingCol = PHPExcel_Cell::columnIndexFromString($startingCol); - $endingCol = PHPExcel_Cell::columnIndexFromString($endingCol); + list($rangeStart, $rangeEnd) = $range; + list($startCol, $startRow) = sscanf($rangeStart,'%[A-Z]%d'); + list($endCol, $endRow) = sscanf($rangeEnd,'%[A-Z]%d'); + $endCol++; // Current data - $currentCol = --$startingCol; - $currentRow = $startingRow; + $currentCol = $startCol; + $currentRow = $startRow; // Loop cells - while ($currentCol < $endingCol) { - $loopColumn = PHPExcel_Cell::stringFromColumnIndex($currentCol); - while ($currentRow <= $endingRow) { - $returnValue[] = $loopColumn.$currentRow; + while ($currentCol != $endCol) { + while ($currentRow <= $endRow) { + $returnValue[] = $currentCol.$currentRow; ++$currentRow; } ++$currentCol; - $currentRow = $startingRow; + $currentRow = $startRow; } } } diff --git a/libraries/PHPExcel/PHPExcel/Cell/AdvancedValueBinder.php b/libraries/PHPExcel/PHPExcel/Cell/AdvancedValueBinder.php index 51268112f..df959dfa5 100644 --- a/libraries/PHPExcel/PHPExcel/Cell/AdvancedValueBinder.php +++ b/libraries/PHPExcel/PHPExcel/Cell/AdvancedValueBinder.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,18 +20,28 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ +/** PHPExcel root directory */ +if (!defined('PHPEXCEL_ROOT')) { + /** + * @ignore + */ + define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); + require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); +} + + /** * PHPExcel_Cell_AdvancedValueBinder * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder { @@ -54,14 +64,27 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder // Style logic - strings if ($dataType === PHPExcel_Cell_DataType::TYPE_STRING && !$value instanceof PHPExcel_RichText) { + // Test for booleans using locale-setting + if ($value == PHPExcel_Calculation::getTRUE()) { + $cell->setValueExplicit( True, PHPExcel_Cell_DataType::TYPE_BOOL); + return true; + } elseif($value == PHPExcel_Calculation::getFALSE()) { + $cell->setValueExplicit( False, PHPExcel_Cell_DataType::TYPE_BOOL); + return true; + } + + // Check for number in scientific format + if (preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NUMBER.'$/', $value)) { + $cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC); + return true; + } + // Check for percentage if (preg_match('/^\-?[0-9]*\.?[0-9]*\s?\%$/', $value)) { // Convert value to number $cell->setValueExplicit( (float)str_replace('%', '', $value) / 100, PHPExcel_Cell_DataType::TYPE_NUMERIC); - // Set style $cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE ); - return true; } @@ -69,13 +92,10 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) { list($h, $m) = explode(':', $value); $days = $h / 24 + $m / 1440; - // Convert value to number $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC); - // Set style $cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3 ); - return true; } @@ -83,29 +103,24 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) { list($h, $m, $s) = explode(':', $value); $days = $h / 24 + $m / 1440 + $s / 86400; - // Convert value to number $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC); - // Set style $cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4 ); - return true; } // Check for datetime, e.g. '2008-12-31', '2008-12-31 15:59', '2008-12-31 15:59:10' - if (($v = PHPExcel_Shared_Date::stringToExcel($value)) !== false) { - // Convert value to Excel date - $cell->setValueExplicit($v, PHPExcel_Cell_DataType::TYPE_NUMERIC); - - // Set style. Either there is a time part or not. Look for ':' + if (($d = PHPExcel_Shared_Date::stringToExcel($value)) !== false) { + // Convert value to number + $cell->setValueExplicit($d, PHPExcel_Cell_DataType::TYPE_NUMERIC); + // Determine style. Either there is a time part or not. Look for ':' if (strpos($value, ':') !== false) { $formatCode = 'yyyy-mm-dd h:mm'; } else { $formatCode = 'yyyy-mm-dd'; } $cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode($formatCode); - return true; } @@ -113,10 +128,8 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder if (strpos($value, "\n") !== false) { $value = PHPExcel_Shared_String::SanitizeUTF8($value); $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING); - // Set style $cell->getParent()->getStyle( $cell->getCoordinate() )->getAlignment()->setWrapText(true); - return true; } } diff --git a/libraries/PHPExcel/PHPExcel/Cell/DataType.php b/libraries/PHPExcel/PHPExcel/Cell/DataType.php index d542cab4e..3143cded7 100644 --- a/libraries/PHPExcel/PHPExcel/Cell/DataType.php +++ b/libraries/PHPExcel/PHPExcel/Cell/DataType.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,11 +31,12 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Cell_DataType { /* Data types */ + const TYPE_STRING2 = 'str'; const TYPE_STRING = 's'; const TYPE_FORMULA = 'f'; const TYPE_NUMERIC = 'n'; diff --git a/libraries/PHPExcel/PHPExcel/Cell/DataValidation.php b/libraries/PHPExcel/PHPExcel/Cell/DataValidation.php index db1b497e8..950c47709 100644 --- a/libraries/PHPExcel/PHPExcel/Cell/DataValidation.php +++ b/libraries/PHPExcel/PHPExcel/Cell/DataValidation.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Cell_DataValidation { diff --git a/libraries/PHPExcel/PHPExcel/Cell/DefaultValueBinder.php b/libraries/PHPExcel/PHPExcel/Cell/DefaultValueBinder.php index ad5ae468d..07134633f 100644 --- a/libraries/PHPExcel/PHPExcel/Cell/DefaultValueBinder.php +++ b/libraries/PHPExcel/PHPExcel/Cell/DefaultValueBinder.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,18 +20,28 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ +/** PHPExcel root directory */ +if (!defined('PHPEXCEL_ROOT')) { + /** + * @ignore + */ + define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); + require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); +} + + /** * PHPExcel_Cell_DefaultValueBinder * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder { diff --git a/libraries/PHPExcel/PHPExcel/Cell/Hyperlink.php b/libraries/PHPExcel/PHPExcel/Cell/Hyperlink.php index 994cef51c..dba5e776b 100644 --- a/libraries/PHPExcel/PHPExcel/Cell/Hyperlink.php +++ b/libraries/PHPExcel/PHPExcel/Cell/Hyperlink.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Cell_Hyperlink { diff --git a/libraries/PHPExcel/PHPExcel/Cell/IValueBinder.php b/libraries/PHPExcel/PHPExcel/Cell/IValueBinder.php index c14d630a4..b175705a5 100644 --- a/libraries/PHPExcel/PHPExcel/Cell/IValueBinder.php +++ b/libraries/PHPExcel/PHPExcel/Cell/IValueBinder.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Cell - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ interface PHPExcel_Cell_IValueBinder { diff --git a/libraries/PHPExcel/PHPExcel/Comment.php b/libraries/PHPExcel/PHPExcel/Comment.php index 432cfe1ea..17fac71d3 100644 --- a/libraries/PHPExcel/PHPExcel/Comment.php +++ b/libraries/PHPExcel/PHPExcel/Comment.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Comment implements PHPExcel_IComparable { @@ -91,6 +91,13 @@ class PHPExcel_Comment implements PHPExcel_IComparable */ private $_fillColor; + /** + * Alignment + * + * @var string + */ + private $_alignment; + /** * Create a new PHPExcel_Comment * @@ -99,9 +106,10 @@ class PHPExcel_Comment implements PHPExcel_IComparable public function __construct() { // Initialise variables - $this->_author = 'Author'; - $this->_text = new PHPExcel_RichText(); - $this->_fillColor = new PHPExcel_Style_Color('FFFFFFE1'); + $this->_author = 'Author'; + $this->_text = new PHPExcel_RichText(); + $this->_fillColor = new PHPExcel_Style_Color('FFFFFFE1'); + $this->_alignment = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL; } /** @@ -253,6 +261,26 @@ class PHPExcel_Comment implements PHPExcel_IComparable return $this->_fillColor; } + /** + * Set Alignment + * + * @param string $pValue + * @return PHPExcel_Comment + */ + public function setAlignment($pValue = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL) { + $this->_alignment = $pValue; + return $this; + } + + /** + * Get Alignment + * + * @return string + */ + public function getAlignment() { + return $this->_alignment; + } + /** * Get hash code * @@ -268,6 +296,7 @@ class PHPExcel_Comment implements PHPExcel_IComparable . $this->_marginTop . ($this->_visible ? 1 : 0) . $this->_fillColor->getHashCode() + . $this->_alignment . __CLASS__ ); } diff --git a/libraries/PHPExcel/PHPExcel/DocumentProperties.php b/libraries/PHPExcel/PHPExcel/DocumentProperties.php index d6d928ecc..e1bd0ba0d 100644 --- a/libraries/PHPExcel/PHPExcel/DocumentProperties.php +++ b/libraries/PHPExcel/PHPExcel/DocumentProperties.php @@ -1,354 +1,465 @@ _creator = 'Unknown Creator'; - $this->_lastModifiedBy = $this->_creator; - $this->_created = time(); - $this->_modified = time(); - $this->_title = "Untitled Spreadsheet"; - $this->_subject = ''; - $this->_description = ''; - $this->_keywords = ''; - $this->_category = ''; - $this->_manager = ''; - $this->_company = 'Microsoft Corporation'; - } + /** + * Custom Properties + * + * @var string + */ + private $_customProperties = array(); - /** - * Get Creator - * - * @return string - */ - public function getCreator() { - return $this->_creator; - } - /** - * Set Creator - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setCreator($pValue = '') { - $this->_creator = $pValue; - return $this; - } + /** + * Create a new PHPExcel_DocumentProperties + */ + public function __construct() + { + // Initialise values + $this->_lastModifiedBy = $this->_creator; + $this->_created = time(); + $this->_modified = time(); + } - /** - * Get Last Modified By - * - * @return string - */ - public function getLastModifiedBy() { - return $this->_lastModifiedBy; - } + /** + * Get Creator + * + * @return string + */ + public function getCreator() { + return $this->_creator; + } - /** - * Set Last Modified By - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setLastModifiedBy($pValue = '') { - $this->_lastModifiedBy = $pValue; - return $this; - } + /** + * Set Creator + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setCreator($pValue = '') { + $this->_creator = $pValue; + return $this; + } - /** - * Get Created - * - * @return datetime - */ - public function getCreated() { - return $this->_created; - } + /** + * Get Last Modified By + * + * @return string + */ + public function getLastModifiedBy() { + return $this->_lastModifiedBy; + } - /** - * Set Created - * - * @param datetime $pValue - * @return PHPExcel_DocumentProperties - */ - public function setCreated($pValue = null) { - if (is_null($pValue)) { - $pValue = time(); - } - $this->_created = $pValue; - return $this; - } + /** + * Set Last Modified By + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setLastModifiedBy($pValue = '') { + $this->_lastModifiedBy = $pValue; + return $this; + } - /** - * Get Modified - * - * @return datetime - */ - public function getModified() { - return $this->_modified; - } + /** + * Get Created + * + * @return datetime + */ + public function getCreated() { + return $this->_created; + } - /** - * Set Modified - * - * @param datetime $pValue - * @return PHPExcel_DocumentProperties - */ - public function setModified($pValue = null) { - if (is_null($pValue)) { - $pValue = time(); - } - $this->_modified = $pValue; - return $this; - } + /** + * Set Created + * + * @param datetime $pValue + * @return PHPExcel_DocumentProperties + */ + public function setCreated($pValue = null) { + if (is_null($pValue)) { + $pValue = time(); + } elseif (is_string($pValue)) { + if (is_numeric($pValue)) { + $pValue = intval($pValue); + } else { + $pValue = strtotime($pValue); + } + } - /** - * Get Title - * - * @return string - */ - public function getTitle() { - return $this->_title; - } + $this->_created = $pValue; + return $this; + } - /** - * Set Title - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setTitle($pValue = '') { - $this->_title = $pValue; - return $this; - } + /** + * Get Modified + * + * @return datetime + */ + public function getModified() { + return $this->_modified; + } - /** - * Get Description - * - * @return string - */ - public function getDescription() { - return $this->_description; - } + /** + * Set Modified + * + * @param datetime $pValue + * @return PHPExcel_DocumentProperties + */ + public function setModified($pValue = null) { + if (is_null($pValue)) { + $pValue = time(); + } elseif (is_string($pValue)) { + if (is_numeric($pValue)) { + $pValue = intval($pValue); + } else { + $pValue = strtotime($pValue); + } + } - /** - * Set Description - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setDescription($pValue = '') { - $this->_description = $pValue; - return $this; - } + $this->_modified = $pValue; + return $this; + } - /** - * Get Subject - * - * @return string - */ - public function getSubject() { - return $this->_subject; - } + /** + * Get Title + * + * @return string + */ + public function getTitle() { + return $this->_title; + } - /** - * Set Subject - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setSubject($pValue = '') { - $this->_subject = $pValue; - return $this; - } + /** + * Set Title + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setTitle($pValue = '') { + $this->_title = $pValue; + return $this; + } - /** - * Get Keywords - * - * @return string - */ - public function getKeywords() { - return $this->_keywords; - } + /** + * Get Description + * + * @return string + */ + public function getDescription() { + return $this->_description; + } - /** - * Set Keywords - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setKeywords($pValue = '') { - $this->_keywords = $pValue; - return $this; - } + /** + * Set Description + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setDescription($pValue = '') { + $this->_description = $pValue; + return $this; + } - /** - * Get Category - * - * @return string - */ - public function getCategory() { - return $this->_category; - } + /** + * Get Subject + * + * @return string + */ + public function getSubject() { + return $this->_subject; + } - /** - * Set Category - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setCategory($pValue = '') { - $this->_category = $pValue; - return $this; - } + /** + * Set Subject + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setSubject($pValue = '') { + $this->_subject = $pValue; + return $this; + } - /** - * Get Company - * - * @return string - */ - public function getCompany() { - return $this->_company; - } + /** + * Get Keywords + * + * @return string + */ + public function getKeywords() { + return $this->_keywords; + } - /** - * Set Company - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setCompany($pValue = '') { - $this->_company = $pValue; - return $this; - } + /** + * Set Keywords + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setKeywords($pValue = '') { + $this->_keywords = $pValue; + return $this; + } - /** - * Get Manager - * - * @return string - */ - public function getManager() { - return $this->_manager; - } + /** + * Get Category + * + * @return string + */ + public function getCategory() { + return $this->_category; + } - /** - * Set Manager - * - * @param string $pValue - * @return PHPExcel_DocumentProperties - */ - public function setManager($pValue = '') { - $this->_manager = $pValue; - return $this; - } + /** + * Set Category + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setCategory($pValue = '') { + $this->_category = $pValue; + return $this; + } + + /** + * Get Company + * + * @return string + */ + public function getCompany() { + return $this->_company; + } + + /** + * Set Company + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setCompany($pValue = '') { + $this->_company = $pValue; + return $this; + } + + /** + * Get Manager + * + * @return string + */ + public function getManager() { + return $this->_manager; + } + + /** + * Set Manager + * + * @param string $pValue + * @return PHPExcel_DocumentProperties + */ + public function setManager($pValue = '') { + $this->_manager = $pValue; + return $this; + } + + /** + * Get a List of Custom Property Names + * + * @return array of string + */ + public function getCustomProperties() { + return array_keys($this->_customProperties); + } + + /** + * Check if a Custom Property is defined + * + * @param string $propertyName + * @return boolean + */ + public function isCustomPropertySet($propertyName) { + return isset($this->_customProperties[$propertyName]); + } + + /** + * Get a Custom Property Value + * + * @param string $propertyName + * @return string + */ + public function getCustomPropertyValue($propertyName) { + if (isset($this->_customProperties[$propertyName])) { + return $this->_customProperties[$propertyName]['value']; + } + + } + + /** + * Get a Custom Property Type + * + * @param string $propertyName + * @return string + */ + public function getCustomPropertyType($propertyName) { + if (isset($this->_customProperties[$propertyName])) { + return $this->_customProperties[$propertyName]['type']; + } + + } + + /** + * Set a Custom Property + * + * @param string $propertyName + * @param mixed $propertyValue + * @param string $propertyType + * 'i' : Integer + * 'f' : Floating Point + * 's' : String + * 'd' : Date/Time + * 'b' : Boolean + * @return PHPExcel_DocumentProperties + */ + public function setCustomProperty($propertyName,$propertyValue='',$propertyType=NULL) { + if ((is_null($propertyType)) || (!in_array($propertyType,array(self::PROPERTY_TYPE_INTEGER, + self::PROPERTY_TYPE_FLOAT, + self::PROPERTY_TYPE_STRING, + self::PROPERTY_TYPE_DATE, + self::PROPERTY_TYPE_BOOLEAN)))) { + if (is_null($propertyValue)) { + $propertyType = self::PROPERTY_TYPE_STRING; + } elseif (is_float($propertyValue)) { + $propertyType = self::PROPERTY_TYPE_FLOAT; + } elseif(is_int($propertyValue)) { + $propertyType = self::PROPERTY_TYPE_INTEGER; + } elseif (is_bool($propertyValue)) { + $propertyType = self::PROPERTY_TYPE_BOOLEAN; + } else { + $propertyType = self::PROPERTY_TYPE_STRING; + } + } + + $this->_customProperties[$propertyName] = array('value' => $propertyValue, 'type' => $propertyType); + return $this; + } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. @@ -363,4 +474,115 @@ class PHPExcel_DocumentProperties } } } + + public static function convertProperty($propertyValue,$propertyType) { + switch ($propertyType) { + case 'empty' : // Empty + return ''; + break; + case 'null' : // Null + return NULL; + break; + case 'i1' : // 1-Byte Signed Integer + case 'i2' : // 2-Byte Signed Integer + case 'i4' : // 4-Byte Signed Integer + case 'i8' : // 8-Byte Signed Integer + case 'int' : // Integer + return (int) $propertyValue; + break; + case 'ui1' : // 1-Byte Unsigned Integer + case 'ui2' : // 2-Byte Unsigned Integer + case 'ui4' : // 4-Byte Unsigned Integer + case 'ui8' : // 8-Byte Unsigned Integer + case 'uint' : // Unsigned Integer + return abs((int) $propertyValue); + break; + case 'r4' : // 4-Byte Real Number + case 'r8' : // 8-Byte Real Number + case 'decimal' : // Decimal + return (float) $propertyValue; + break; + case 'lpstr' : // LPSTR + case 'lpwstr' : // LPWSTR + case 'bstr' : // Basic String + return $propertyValue; + break; + case 'date' : // Date and Time + case 'filetime' : // File Time + return strtotime($propertyValue); + break; + case 'bool' : // Boolean + return ($propertyValue == 'true') ? True : False; + break; + case 'cy' : // Currency + case 'error' : // Error Status Code + case 'vector' : // Vector + case 'array' : // Array + case 'blob' : // Binary Blob + case 'oblob' : // Binary Blob Object + case 'stream' : // Binary Stream + case 'ostream' : // Binary Stream Object + case 'storage' : // Binary Storage + case 'ostorage' : // Binary Storage Object + case 'vstream' : // Binary Versioned Stream + case 'clsid' : // Class ID + case 'cf' : // Clipboard Data + return $propertyValue; + break; + } + return $propertyValue; + } + + public static function convertPropertyType($propertyType) { + switch ($propertyType) { + case 'i1' : // 1-Byte Signed Integer + case 'i2' : // 2-Byte Signed Integer + case 'i4' : // 4-Byte Signed Integer + case 'i8' : // 8-Byte Signed Integer + case 'int' : // Integer + case 'ui1' : // 1-Byte Unsigned Integer + case 'ui2' : // 2-Byte Unsigned Integer + case 'ui4' : // 4-Byte Unsigned Integer + case 'ui8' : // 8-Byte Unsigned Integer + case 'uint' : // Unsigned Integer + return self::PROPERTY_TYPE_INTEGER; + break; + case 'r4' : // 4-Byte Real Number + case 'r8' : // 8-Byte Real Number + case 'decimal' : // Decimal + return self::PROPERTY_TYPE_FLOAT; + break; + case 'empty' : // Empty + case 'null' : // Null + case 'lpstr' : // LPSTR + case 'lpwstr' : // LPWSTR + case 'bstr' : // Basic String + return self::PROPERTY_TYPE_STRING; + break; + case 'date' : // Date and Time + case 'filetime' : // File Time + return self::PROPERTY_TYPE_DATE; + break; + case 'bool' : // Boolean + return self::PROPERTY_TYPE_BOOLEAN; + break; + case 'cy' : // Currency + case 'error' : // Error Status Code + case 'vector' : // Vector + case 'array' : // Array + case 'blob' : // Binary Blob + case 'oblob' : // Binary Blob Object + case 'stream' : // Binary Stream + case 'ostream' : // Binary Stream Object + case 'storage' : // Binary Storage + case 'ostorage' : // Binary Storage Object + case 'vstream' : // Binary Versioned Stream + case 'clsid' : // Class ID + case 'cf' : // Clipboard Data + return self::PROPERTY_TYPE_UNKNOWN; + break; + } + return self::PROPERTY_TYPE_UNKNOWN; + } + } diff --git a/libraries/PHPExcel/PHPExcel/DocumentSecurity.php b/libraries/PHPExcel/PHPExcel/DocumentSecurity.php index a6de9ee39..f10902487 100644 --- a/libraries/PHPExcel/PHPExcel/DocumentSecurity.php +++ b/libraries/PHPExcel/PHPExcel/DocumentSecurity.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_DocumentSecurity { diff --git a/libraries/PHPExcel/PHPExcel/HashTable.php b/libraries/PHPExcel/PHPExcel/HashTable.php index 219167231..8ca647e8b 100644 --- a/libraries/PHPExcel/PHPExcel/HashTable.php +++ b/libraries/PHPExcel/PHPExcel/HashTable.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,161 +30,163 @@ * PHPExcel_HashTable * * @category PHPExcel - * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_HashTable { - /** - * HashTable elements - * - * @var array - */ - public $_items = array(); + /** + * HashTable elements + * + * @var array + */ + public $_items = array(); - /** - * HashTable key map - * - * @var array - */ - public $_keyMap = array(); + /** + * HashTable key map + * + * @var array + */ + public $_keyMap = array(); - /** - * Create a new PHPExcel_HashTable - * - * @param PHPExcel_IComparable[] $pSource Optional source array to create HashTable from - * @throws Exception - */ - public function __construct($pSource = null) - { - if (!is_null($pSource)) { - // Create HashTable - $this->addFromSource($pSource); - } - } + /** + * Create a new PHPExcel_HashTable + * + * @param PHPExcel_IComparable[] $pSource Optional source array to create HashTable from + * @throws Exception + */ + public function __construct($pSource = null) + { + if (!is_null($pSource)) { + // Create HashTable + $this->addFromSource($pSource); + } + } - /** - * Add HashTable items from source - * - * @param PHPExcel_IComparable[] $pSource Source array to create HashTable from - * @throws Exception - */ - public function addFromSource($pSource = null) { - // Check if an array was passed - if ($pSource == null) { - return; - } else if (!is_array($pSource)) { - throw new Exception('Invalid array parameter passed.'); - } + /** + * Add HashTable items from source + * + * @param PHPExcel_IComparable[] $pSource Source array to create HashTable from + * @throws Exception + */ + public function addFromSource($pSource = null) { + // Check if an array was passed + if ($pSource == null) { + return; + } else if (!is_array($pSource)) { + throw new Exception('Invalid array parameter passed.'); + } - foreach ($pSource as $item) { - $this->add($item); - } - } + foreach ($pSource as $item) { + $this->add($item); + } + } - /** - * Add HashTable item - * - * @param PHPExcel_IComparable $pSource Item to add - * @throws Exception - */ - public function add(PHPExcel_IComparable $pSource = null) { - if (!isset($this->_items[ $pSource->getHashCode() ])) { - $this->_items[ $pSource->getHashCode() ] = $pSource; - $this->_keyMap[ count($this->_items) - 1 ] = $pSource->getHashCode(); - } - } + /** + * Add HashTable item + * + * @param PHPExcel_IComparable $pSource Item to add + * @throws Exception + */ + public function add(PHPExcel_IComparable $pSource = null) { + $hash = $pSource->getHashCode(); + if (!isset($this->_items[$hash])) { + $this->_items[$hash] = $pSource; + $this->_keyMap[count($this->_items) - 1] = $hash; + } + } - /** - * Remove HashTable item - * - * @param PHPExcel_IComparable $pSource Item to remove - * @throws Exception - */ - public function remove(PHPExcel_IComparable $pSource = null) { - if (isset($this->_items[ $pSource->getHashCode() ])) { - unset($this->_items[ $pSource->getHashCode() ]); + /** + * Remove HashTable item + * + * @param PHPExcel_IComparable $pSource Item to remove + * @throws Exception + */ + public function remove(PHPExcel_IComparable $pSource = null) { + $hash = $pSource->getHashCode(); + if (isset($this->_items[$hash])) { + unset($this->_items[$hash]); - $deleteKey = -1; - foreach ($this->_keyMap as $key => $value) { - if ($deleteKey >= 0) { - $this->_keyMap[$key - 1] = $value; - } + $deleteKey = -1; + foreach ($this->_keyMap as $key => $value) { + if ($deleteKey >= 0) { + $this->_keyMap[$key - 1] = $value; + } - if ($value == $pSource->getHashCode()) { - $deleteKey = $key; - } - } - unset($this->_keyMap[ count($this->_keyMap) - 1 ]); - } - } + if ($value == $hash) { + $deleteKey = $key; + } + } + unset($this->_keyMap[count($this->_keyMap) - 1]); + } + } - /** - * Clear HashTable - * - */ - public function clear() { - $this->_items = array(); - $this->_keyMap = array(); - } + /** + * Clear HashTable + * + */ + public function clear() { + $this->_items = array(); + $this->_keyMap = array(); + } - /** - * Count - * - * @return int - */ - public function count() { - return count($this->_items); - } + /** + * Count + * + * @return int + */ + public function count() { + return count($this->_items); + } - /** - * Get index for hash code - * - * @param string $pHashCode - * @return int Index - */ - public function getIndexForHashCode($pHashCode = '') { - return array_search($pHashCode, $this->_keyMap); - } + /** + * Get index for hash code + * + * @param string $pHashCode + * @return int Index + */ + public function getIndexForHashCode($pHashCode = '') { + return array_search($pHashCode, $this->_keyMap); + } - /** - * Get by index - * - * @param int $pIndex - * @return PHPExcel_IComparable - * - */ - public function getByIndex($pIndex = 0) { - if (isset($this->_keyMap[$pIndex])) { - return $this->getByHashCode( $this->_keyMap[$pIndex] ); - } + /** + * Get by index + * + * @param int $pIndex + * @return PHPExcel_IComparable + * + */ + public function getByIndex($pIndex = 0) { + if (isset($this->_keyMap[$pIndex])) { + return $this->getByHashCode( $this->_keyMap[$pIndex] ); + } - return null; - } + return null; + } - /** - * Get by hashcode - * - * @param string $pHashCode - * @return PHPExcel_IComparable - * - */ - public function getByHashCode($pHashCode = '') { - if (isset($this->_items[$pHashCode])) { - return $this->_items[$pHashCode]; - } + /** + * Get by hashcode + * + * @param string $pHashCode + * @return PHPExcel_IComparable + * + */ + public function getByHashCode($pHashCode = '') { + if (isset($this->_items[$pHashCode])) { + return $this->_items[$pHashCode]; + } - return null; - } + return null; + } - /** - * HashTable to array - * - * @return PHPExcel_IComparable[] - */ - public function toArray() { - return $this->_items; - } + /** + * HashTable to array + * + * @return PHPExcel_IComparable[] + */ + public function toArray() { + return $this->_items; + } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. diff --git a/libraries/PHPExcel/PHPExcel/IComparable.php b/libraries/PHPExcel/PHPExcel/IComparable.php index 0a51b069e..777c1cd90 100644 --- a/libraries/PHPExcel/PHPExcel/IComparable.php +++ b/libraries/PHPExcel/PHPExcel/IComparable.php @@ -18,9 +18,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -29,7 +29,7 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ interface PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/IOFactory.php b/libraries/PHPExcel/PHPExcel/IOFactory.php index a3650bedc..f8e2e8c28 100644 --- a/libraries/PHPExcel/PHPExcel/IOFactory.php +++ b/libraries/PHPExcel/PHPExcel/IOFactory.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,12 +33,6 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** @@ -46,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) { * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_IOFactory { @@ -75,7 +69,7 @@ class PHPExcel_IOFactory 'Excel2003XML', 'OOCalc', 'SYLK', - 'Serialized', + 'Gnumeric', 'CSV', ); @@ -247,6 +241,9 @@ class PHPExcel_IOFactory case 'xml': $reader = self::createReader('Excel2003XML'); break; + case 'gnumeric': + $reader = self::createReader('Gnumeric'); + break; case 'csv': // Do nothing // We must not try to use CSV reader since it loads diff --git a/libraries/PHPExcel/PHPExcel/NamedRange.php b/libraries/PHPExcel/PHPExcel/NamedRange.php index 992c2fa3f..9afb0f9b4 100644 --- a/libraries/PHPExcel/PHPExcel/NamedRange.php +++ b/libraries/PHPExcel/PHPExcel/NamedRange.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_NamedRange { diff --git a/libraries/PHPExcel/PHPExcel/Reader/CSV.php b/libraries/PHPExcel/PHPExcel/Reader/CSV.php index 086c9482d..3bac3af0f 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/CSV.php +++ b/libraries/PHPExcel/PHPExcel/Reader/CSV.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,12 +33,6 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** @@ -46,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) { * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader { @@ -56,7 +50,7 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader * @access private * @var string */ - private $_inputEncoding; + private $_inputEncoding = 'UTF-8'; /** * Delimiter @@ -64,7 +58,7 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader * @access private * @var string */ - private $_delimiter; + private $_delimiter = ','; /** * Enclosure @@ -72,7 +66,7 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader * @access private * @var string */ - private $_enclosure; + private $_enclosure = '"'; /** * Line ending @@ -80,7 +74,7 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader * @access private * @var string */ - private $_lineEnding; + private $_lineEnding = PHP_EOL; /** * Sheet index to read @@ -88,7 +82,24 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader * @access private * @var int */ - private $_sheetIndex; + private $_sheetIndex = 0; + + /** + * Load rows contiguously + * + * @access private + * @var int + */ + private $_contiguous = false; + + + /** + * Row counter for loading rows contiguously + * + * @access private + * @var int + */ + private $_contiguousRow = -1; /** * PHPExcel_Reader_IReadFilter instance @@ -102,12 +113,7 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader * Create a new PHPExcel_Reader_CSV */ public function __construct() { - $this->_inputEncoding = 'UTF-8'; - $this->_delimiter = ','; - $this->_enclosure = '"'; - $this->_lineEnding = PHP_EOL; - $this->_sheetIndex = 0; - $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter(); + $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter(); } // function __construct() /** @@ -223,37 +229,64 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader fgets($fileHandle, 4) == "\xEF\xBB\xBF" ? fseek($fileHandle, 3) : fseek($fileHandle, 0); break; + case 'UTF-16LE': + fgets($fileHandle, 3) == "\xFF\xFE" ? + fseek($fileHandle, 2) : fseek($fileHandle, 0); + break; + case 'UTF-16BE': + fgets($fileHandle, 3) == "\xFE\xFF" ? + fseek($fileHandle, 2) : fseek($fileHandle, 0); + break; + case 'UTF-32LE': + fgets($fileHandle, 5) == "\xFF\xFE\x00\x00" ? + fseek($fileHandle, 4) : fseek($fileHandle, 0); + break; + case 'UTF-32BE': + fgets($fileHandle, 5) == "\x00\x00\xFE\xFF" ? + fseek($fileHandle, 4) : fseek($fileHandle, 0); + break; default: break; } - // Loop through file - $currentRow = 0; - $rowData = array(); + $escapeEnclosures = array( "\\" . $this->_enclosure, + $this->_enclosure . $this->_enclosure + ); + + // Set our starting row based on whether we're in contiguous mode or not + $currentRow = 1; + if ($this->_contiguous) { + $currentRow = ($this->_contiguousRow == -1) ? $objPHPExcel->getActiveSheet()->getHighestRow(): $this->_contiguousRow; + } + + // Loop through each line of the file in turn while (($rowData = fgetcsv($fileHandle, 0, $this->_delimiter, $this->_enclosure)) !== FALSE) { - ++$currentRow; - $rowDataCount = count($rowData); - for ($i = 0; $i < $rowDataCount; ++$i) { - $columnLetter = PHPExcel_Cell::stringFromColumnIndex($i); - if ($rowData[$i] != '' && $this->_readFilter->readCell($columnLetter, $currentRow)) { + $columnLetter = 'A'; + foreach($rowData as $rowDatum) { + if ($rowDatum != '' && $this->_readFilter->readCell($columnLetter, $currentRow)) { // Unescape enclosures - $rowData[$i] = str_replace("\\" . $this->_enclosure, $this->_enclosure, $rowData[$i]); - $rowData[$i] = str_replace($this->_enclosure . $this->_enclosure, $this->_enclosure, $rowData[$i]); + $rowDatum = str_replace($escapeEnclosures, $this->_enclosure, $rowDatum); // Convert encoding if necessary if ($this->_inputEncoding !== 'UTF-8') { - $rowData[$i] = PHPExcel_Shared_String::ConvertEncoding($rowData[$i], 'UTF-8', $this->_inputEncoding); + $rowDatum = PHPExcel_Shared_String::ConvertEncoding($rowDatum, 'UTF-8', $this->_inputEncoding); } // Set cell value - $objPHPExcel->getActiveSheet()->getCell($columnLetter . $currentRow)->setValue($rowData[$i]); + $objPHPExcel->getActiveSheet()->getCell($columnLetter . $currentRow)->setValue($rowDatum); } + ++$columnLetter; } + ++$currentRow; } // Close file fclose($fileHandle); + if ($this->_contiguous) { + $this->_contiguousRow = $currentRow; + } + // Return return $objPHPExcel; } // function loadIntoExisting() @@ -348,4 +381,31 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader $this->_sheetIndex = $pValue; return $this; } // function setSheetIndex() + + /** + * Set Contiguous + * + * @access public + * @param string $pValue Input encoding + */ + public function setContiguous($contiguous = false) + { + $this->_contiguous = (bool)$contiguous; + if (!$contiguous) { + $this->_contiguousRow = -1; + } + + return $this; + } // function setInputEncoding() + + /** + * Get Contiguous + * + * @access public + * @return boolean + */ + public function getContiguous() { + return $this->_contiguous; + } // function getSheetIndex() + } diff --git a/libraries/PHPExcel/PHPExcel/Reader/DefaultReadFilter.php b/libraries/PHPExcel/PHPExcel/Reader/DefaultReadFilter.php index e83ac9ade..9255f2dfa 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/DefaultReadFilter.php +++ b/libraries/PHPExcel/PHPExcel/Reader/DefaultReadFilter.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,12 +33,6 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** @@ -46,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) { * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_DefaultReadFilter implements PHPExcel_Reader_IReadFilter { diff --git a/libraries/PHPExcel/PHPExcel/Reader/Excel2003XML.php b/libraries/PHPExcel/PHPExcel/Reader/Excel2003XML.php index 99f00eda9..cb91a746b 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/Excel2003XML.php +++ b/libraries/PHPExcel/PHPExcel/Reader/Excel2003XML.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,12 +33,6 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** @@ -46,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) { * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader { @@ -64,13 +58,6 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader */ private $_loadSheetsOnly = null; - /** - * Sheet index to read - * - * @var int - */ - private $_sheetIndex; - /** * Formats * @@ -99,7 +86,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader * Set read data only * * @param boolean $pValue - * @return PHPExcel_Reader_Excel2007 + * @return PHPExcel_Reader_Excel2003XML */ public function setReadDataOnly($pValue = false) { $this->_readDataOnly = $pValue; @@ -120,7 +107,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader * Set which sheets to load * * @param mixed $value - * @return PHPExcel_Reader_Excel2007 + * @return PHPExcel_Reader_Excel2003XML */ public function setLoadSheetsOnly($value = null) { @@ -132,7 +119,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader /** * Set all sheets to load * - * @return PHPExcel_Reader_Excel2007 + * @return PHPExcel_Reader_Excel2003XML */ public function setLoadAllSheets() { @@ -153,7 +140,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader * Set read filter * * @param PHPExcel_Reader_IReadFilter $pValue - * @return PHPExcel_Reader_Excel2007 + * @return PHPExcel_Reader_Excel2003XML */ public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) { $this->_readFilter = $pValue; @@ -164,7 +151,6 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader * Create a new PHPExcel_Reader_Excel2003XML */ public function __construct() { - $this->_sheetIndex = 0; $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter(); } @@ -188,7 +174,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader // $signature = array( - '', + '' ); @@ -202,16 +188,10 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader $data = fread($fh, 2048); fclose($fh); - $headers = explode("\n",$data); $valid = true; - foreach($signature as $key => $match) { - if (isset($headers[$key])) { - $line = trim(rtrim($headers[$key], "\r\n")); - if ($line != $match) { - $valid = false; - break; - } - } else { + foreach($signature as $match) { + // every part of the signature must be present + if (strpos($data, $match) === false) { $valid = false; break; } @@ -220,6 +200,34 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader return $valid; } + /** + * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object + * + * @param string $pFilename + * @throws Exception + */ + public function listWorksheetNames($pFilename) + { + // Check if file exists + if (!file_exists($pFilename)) { + throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); + } + + $worksheetNames = array(); + + $xml = simplexml_load_file($pFilename); + $namespaces = $xml->getNamespaces(true); + + $xml_ss = $xml->children($namespaces['ss']); + foreach($xml_ss->Worksheet as $worksheet) { + $worksheet_ss = $worksheet->attributes($namespaces['ss']); + $worksheetNames[] = $worksheet_ss['Name']; + } + + return $worksheetNames; + } + + /** * Loads PHPExcel from file * @@ -272,6 +280,11 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader return $pixels; } + + private static function _hex2str($hex) { + return chr(hexdec($hex[1])); + } + /** * Loads PHPExcel from file into PHPExcel instance * @@ -307,6 +320,9 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY ); + $timezoneObj = new DateTimeZone('Europe/London'); + $GMT = new DateTimeZone('UTC'); + // Check if file exists if (!file_exists($pFilename)) { @@ -315,48 +331,79 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader $xml = simplexml_load_file($pFilename); $namespaces = $xml->getNamespaces(true); -// echo '
';
-//		print_r($namespaces);
-//		echo '

'; -// -// echo '
';
-//		print_r($xml);
-//		echo '

'; -// + $docProps = $objPHPExcel->getProperties(); - foreach($xml->DocumentProperties[0] as $propertyName => $propertyValue) { - switch ($propertyName) { - case 'Title' : - $docProps->setTitle($propertyValue); - break; - case 'Subject' : - $docProps->setSubject($propertyValue); - break; - case 'Author' : - $docProps->setCreator($propertyValue); - break; - case 'Created' : - $creationDate = strtotime($propertyValue); - $docProps->setCreated($creationDate); - break; - case 'LastAuthor' : - $docProps->setLastModifiedBy($propertyValue); - break; - case 'Company' : - $docProps->setCompany($propertyValue); - break; - case 'Category' : - $docProps->setCategory($propertyValue); - break; - case 'Keywords' : - $docProps->setKeywords($propertyValue); - break; - case 'Description' : - $docProps->setDescription($propertyValue); - break; + if (isset($xml->DocumentProperties[0])) { + foreach($xml->DocumentProperties[0] as $propertyName => $propertyValue) { + switch ($propertyName) { + case 'Title' : + $docProps->setTitle($propertyValue); + break; + case 'Subject' : + $docProps->setSubject($propertyValue); + break; + case 'Author' : + $docProps->setCreator($propertyValue); + break; + case 'Created' : + $creationDate = strtotime($propertyValue); + $docProps->setCreated($creationDate); + break; + case 'LastAuthor' : + $docProps->setLastModifiedBy($propertyValue); + break; + case 'LastSaved' : + $lastSaveDate = strtotime($propertyValue); + $docProps->setModified($lastSaveDate); + break; + case 'Company' : + $docProps->setCompany($propertyValue); + break; + case 'Category' : + $docProps->setCategory($propertyValue); + break; + case 'Manager' : + $docProps->setManager($propertyValue); + break; + case 'Keywords' : + $docProps->setKeywords($propertyValue); + break; + case 'Description' : + $docProps->setDescription($propertyValue); + break; + } + } + } + if (isset($xml->CustomDocumentProperties)) { + foreach($xml->CustomDocumentProperties[0] as $propertyName => $propertyValue) { + $propertyAttributes = $propertyValue->attributes($namespaces['dt']); + $propertyName = preg_replace_callback('/_x([0-9a-z]{4})_/','PHPExcel_Reader_Excel2003XML::_hex2str',$propertyName); + $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_UNKNOWN; + switch((string) $propertyAttributes) { + case 'string' : + $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING; + $propertyValue = trim($propertyValue); + break; + case 'boolean' : + $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_BOOLEAN; + $propertyValue = (bool) $propertyValue; + break; + case 'integer' : + $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_INTEGER; + $propertyValue = intval($propertyValue); + break; + case 'float' : + $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_FLOAT; + $propertyValue = floatval($propertyValue); + break; + case 'dateTime.tz' : + $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_DATE; + $propertyValue = strtotime(trim($propertyValue)); + break; + } + $docProps->setCustomProperty($propertyName,$propertyValue,$propertyType); } } - foreach($xml->Styles[0] as $style) { $style_ss = $style->attributes($namespaces['ss']); @@ -487,13 +534,17 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader // echo '
'; $worksheetID = 0; - foreach($xml->Worksheet as $worksheet) { + $xml_ss = $xml->children($namespaces['ss']); + foreach($xml_ss->Worksheet as $worksheet) { $worksheet_ss = $worksheet->attributes($namespaces['ss']); + if ((isset($this->_loadSheetsOnly)) && (isset($worksheet_ss['Name'])) && (!in_array($worksheet_ss['Name'], $this->_loadSheetsOnly))) { continue; } +// echo '

Worksheet: ',$worksheet_ss['Name'],'

'; +// // Create new Worksheet $objPHPExcel->createSheet(); $objPHPExcel->setActiveSheetIndex($worksheetID); @@ -503,166 +554,220 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader } $columnID = 'A'; - foreach($worksheet->Table->Column as $columnData) { - $columnData_ss = $columnData->attributes($namespaces['ss']); - if (isset($columnData_ss['Index'])) { - $columnID = PHPExcel_Cell::stringFromColumnIndex($columnData_ss['Index']-1); - } - if (isset($columnData_ss['Width'])) { - $columnWidth = $columnData_ss['Width']; -// echo 'Setting column width for '.$columnID.' to '.$columnWidth.'
'; - $objPHPExcel->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4); - } - ++$columnID; - } - - $rowID = 1; - foreach($worksheet->Table->Row as $rowData) { - $row_ss = $rowData->attributes($namespaces['ss']); - if (isset($row_ss['Index'])) { - $rowID = (integer) $row_ss['Index']; - } -// echo 'Row '.$rowID.'
'; - if (isset($row_ss['StyleID'])) { - $rowStyle = $row_ss['StyleID']; - } - if (isset($row_ss['Height'])) { - $rowHeight = $row_ss['Height']; -// echo 'Setting row height to '.$rowHeight.'
'; - $objPHPExcel->getActiveSheet()->getRowDimension($rowID)->setRowHeight($rowHeight); - } - $columnID = 'A'; - foreach($rowData->Cell as $cell) { - - $cell_ss = $cell->attributes($namespaces['ss']); - if (isset($cell_ss['Index'])) { - $columnID = PHPExcel_Cell::stringFromColumnIndex($cell_ss['Index']-1); + if (isset($worksheet->Table->Column)) { + foreach($worksheet->Table->Column as $columnData) { + $columnData_ss = $columnData->attributes($namespaces['ss']); + if (isset($columnData_ss['Index'])) { + $columnID = PHPExcel_Cell::stringFromColumnIndex($columnData_ss['Index']-1); } - $cellRange = $columnID.$rowID; - - if ((isset($cell_ss['MergeAcross'])) || (isset($cell_ss['MergeDown']))) { - $columnTo = $columnID; - if (isset($cell_ss['MergeAcross'])) { - $columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cell_ss['MergeAcross'] -1); - } - $rowTo = $rowID; - if (isset($cell_ss['MergeDown'])) { - $rowTo = $rowTo + $cell_ss['MergeDown']; - } - $cellRange .= ':'.$columnTo.$rowTo; - $objPHPExcel->getActiveSheet()->mergeCells($cellRange); - } - - $hasCalculatedValue = false; - $cellDataFormula = ''; - if (isset($cell_ss['Formula'])) { - $cellDataFormula = $cell_ss['Formula']; - // added this as a check for array formulas - if (isset($cell_ss['ArrayRange'])) { - $cellDataCSEFormula = $cell_ss['ArrayRange']; -// echo "found an array formula at ".$columnID.$rowID."
"; - } - $hasCalculatedValue = true; - } - if (isset($cell->Data)) { - $cellValue = $cellData = $cell->Data; - $type = PHPExcel_Cell_DataType::TYPE_NULL; - $cellData_ss = $cellData->attributes($namespaces['ss']); - if (isset($cellData_ss['Type'])) { - $cellDataType = $cellData_ss['Type']; - switch ($cellDataType) { - /* - const TYPE_STRING = 's'; - const TYPE_FORMULA = 'f'; - const TYPE_NUMERIC = 'n'; - const TYPE_BOOL = 'b'; - const TYPE_NULL = 's'; - const TYPE_INLINE = 'inlineStr'; - const TYPE_ERROR = 'e'; - */ - case 'String' : - $type = PHPExcel_Cell_DataType::TYPE_STRING; - break; - case 'Number' : - $type = PHPExcel_Cell_DataType::TYPE_NUMERIC; - $cellValue = (float) $cellValue; - if (floor($cellValue) == $cellValue) { - $cellValue = (integer) $cellValue; - } - break; - case 'Boolean' : - $type = PHPExcel_Cell_DataType::TYPE_BOOL; - $cellValue = ($cellValue != 0); - break; - case 'DateTime' : - $type = PHPExcel_Cell_DataType::TYPE_NUMERIC; - $cellValue = PHPExcel_Shared_Date::PHPToExcel(strtotime($cellValue)); - break; - case 'Error' : - $type = PHPExcel_Cell_DataType::TYPE_ERROR; - break; - } - } - if ($hasCalculatedValue) { - $type = PHPExcel_Cell_DataType::TYPE_FORMULA; - $columnNumber = PHPExcel_Cell::columnIndexFromString($columnID); - // Convert R1C1 style references to A1 style references (but only when not quoted) - $temp = explode('"',$cellDataFormula); - foreach($temp as $key => &$value) { - // Only replace in alternate array entries (i.e. non-quoted blocks) - if (($key % 2) == 0) { - preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/',$value, $cellReferences,PREG_SET_ORDER+PREG_OFFSET_CAPTURE); - // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way - // through the formula from left to right. Reversing means that we work right to left.through - // the formula - $cellReferences = array_reverse($cellReferences); - // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent, - // then modify the formula to use that new reference - foreach($cellReferences as $cellReference) { - $rowReference = $cellReference[2][0]; - // Empty R reference is the current row - if ($rowReference == '') $rowReference = $rowID; - // Bracketed R references are relative to the current row - if ($rowReference{0} == '[') $rowReference = $rowID + trim($rowReference,'[]'); - $columnReference = $cellReference[4][0]; - // Empty C reference is the current column - if ($columnReference == '') $columnReference = $columnNumber; - // Bracketed C references are relative to the current column - if ($columnReference{0} == '[') $columnReference = $columnNumber + trim($columnReference,'[]'); - $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference; - $value = substr_replace($value,$A1CellReference,$cellReference[0][1],strlen($cellReference[0][0])); - } - } - } - unset($value); - // Then rebuild the formula string - $cellDataFormula = implode('"',$temp); - } - -// echo 'Cell '.$columnID.$rowID.' is a '.$type.' with a value of '.(($hasCalculatedValue) ? $cellDataFormula : $cellValue).'
'; -// - $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $cellValue),$type); - if ($hasCalculatedValue) { -// echo 'Forumla result is '.$cellValue.'
'; - $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($cellValue); - } - } - if (isset($cell_ss['StyleID'])) { - $style = (string) $cell_ss['StyleID']; -// echo 'Cell style for '.$columnID.$rowID.' is '.$style.'
'; - if ((isset($this->_styles[$style])) && (count($this->_styles[$style]) > 0)) { -// echo 'Cell '.$columnID.$rowID.'
'; -// print_r($this->_styles[$style]); -// echo '
'; - if (!$objPHPExcel->getActiveSheet()->cellExists($columnID.$rowID)) { - $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValue(NULL); - } - $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($this->_styles[$style]); - } + if (isset($columnData_ss['Width'])) { + $columnWidth = $columnData_ss['Width']; +// echo 'Setting column width for '.$columnID.' to '.$columnWidth.'
'; + $objPHPExcel->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4); } ++$columnID; } - ++$rowID; + } + + $rowID = 1; + if (isset($worksheet->Table->Row)) { + foreach($worksheet->Table->Row as $rowData) { + $rowHasData = false; + $row_ss = $rowData->attributes($namespaces['ss']); + if (isset($row_ss['Index'])) { + $rowID = (integer) $row_ss['Index']; + } +// echo 'Row '.$rowID.'
'; + + $columnID = 'A'; + foreach($rowData->Cell as $cell) { + + $cell_ss = $cell->attributes($namespaces['ss']); + if (isset($cell_ss['Index'])) { + $columnID = PHPExcel_Cell::stringFromColumnIndex($cell_ss['Index']-1); + } + $cellRange = $columnID.$rowID; + + if (!is_null($this->getReadFilter())) { + if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { + continue; + } + } + + if ((isset($cell_ss['MergeAcross'])) || (isset($cell_ss['MergeDown']))) { + $columnTo = $columnID; + if (isset($cell_ss['MergeAcross'])) { + $columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cell_ss['MergeAcross'] -1); + } + $rowTo = $rowID; + if (isset($cell_ss['MergeDown'])) { + $rowTo = $rowTo + $cell_ss['MergeDown']; + } + $cellRange .= ':'.$columnTo.$rowTo; + $objPHPExcel->getActiveSheet()->mergeCells($cellRange); + } + + $cellIsSet = $hasCalculatedValue = false; + $cellDataFormula = ''; + if (isset($cell_ss['Formula'])) { + $cellDataFormula = $cell_ss['Formula']; + // added this as a check for array formulas + if (isset($cell_ss['ArrayRange'])) { + $cellDataCSEFormula = $cell_ss['ArrayRange']; +// echo "found an array formula at ".$columnID.$rowID."
"; + } + $hasCalculatedValue = true; + } + if (isset($cell->Data)) { + $cellValue = $cellData = $cell->Data; + $type = PHPExcel_Cell_DataType::TYPE_NULL; + $cellData_ss = $cellData->attributes($namespaces['ss']); + if (isset($cellData_ss['Type'])) { + $cellDataType = $cellData_ss['Type']; + switch ($cellDataType) { + /* + const TYPE_STRING = 's'; + const TYPE_FORMULA = 'f'; + const TYPE_NUMERIC = 'n'; + const TYPE_BOOL = 'b'; + const TYPE_NULL = 's'; + const TYPE_INLINE = 'inlineStr'; + const TYPE_ERROR = 'e'; + */ + case 'String' : + $type = PHPExcel_Cell_DataType::TYPE_STRING; + break; + case 'Number' : + $type = PHPExcel_Cell_DataType::TYPE_NUMERIC; + $cellValue = (float) $cellValue; + if (floor($cellValue) == $cellValue) { + $cellValue = (integer) $cellValue; + } + break; + case 'Boolean' : + $type = PHPExcel_Cell_DataType::TYPE_BOOL; + $cellValue = ($cellValue != 0); + break; + case 'DateTime' : + $type = PHPExcel_Cell_DataType::TYPE_NUMERIC; + $cellValue = PHPExcel_Shared_Date::PHPToExcel(strtotime($cellValue)); + break; + case 'Error' : + $type = PHPExcel_Cell_DataType::TYPE_ERROR; + break; + } + } + + if ($hasCalculatedValue) { +// echo 'FORMULA
'; + $type = PHPExcel_Cell_DataType::TYPE_FORMULA; + $columnNumber = PHPExcel_Cell::columnIndexFromString($columnID); + if (substr($cellDataFormula,0,3) == 'of:') { + $cellDataFormula = substr($cellDataFormula,3); +// echo 'Before: ',$cellDataFormula,'
'; + $temp = explode('"',$cellDataFormula); + $key = false; + foreach($temp as &$value) { + // Only replace in alternate array entries (i.e. non-quoted blocks) + if ($key = !$key) { + $value = str_replace(array('[.','.',']'),'',$value); + } + } + } else { + // Convert R1C1 style references to A1 style references (but only when not quoted) +// echo 'Before: ',$cellDataFormula,'
'; + $temp = explode('"',$cellDataFormula); + $key = false; + foreach($temp as &$value) { + // Only replace in alternate array entries (i.e. non-quoted blocks) + if ($key = !$key) { + preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/',$value, $cellReferences,PREG_SET_ORDER+PREG_OFFSET_CAPTURE); + // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way + // through the formula from left to right. Reversing means that we work right to left.through + // the formula + $cellReferences = array_reverse($cellReferences); + // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent, + // then modify the formula to use that new reference + foreach($cellReferences as $cellReference) { + $rowReference = $cellReference[2][0]; + // Empty R reference is the current row + if ($rowReference == '') $rowReference = $rowID; + // Bracketed R references are relative to the current row + if ($rowReference{0} == '[') $rowReference = $rowID + trim($rowReference,'[]'); + $columnReference = $cellReference[4][0]; + // Empty C reference is the current column + if ($columnReference == '') $columnReference = $columnNumber; + // Bracketed C references are relative to the current column + if ($columnReference{0} == '[') $columnReference = $columnNumber + trim($columnReference,'[]'); + $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference; + $value = substr_replace($value,$A1CellReference,$cellReference[0][1],strlen($cellReference[0][0])); + } + } + } + } + unset($value); + // Then rebuild the formula string + $cellDataFormula = implode('"',$temp); +// echo 'After: ',$cellDataFormula,'
'; + } + +// echo 'Cell '.$columnID.$rowID.' is a '.$type.' with a value of '.(($hasCalculatedValue) ? $cellDataFormula : $cellValue).'
'; +// + $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $cellValue),$type); + if ($hasCalculatedValue) { +// echo 'Formula result is '.$cellValue.'
'; + $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($cellValue); + } + $cellIsSet = $rowHasData = true; + } + + if (isset($cell->Comment)) { +// echo 'comment found
'; + $commentAttributes = $cell->Comment->attributes($namespaces['ss']); + $author = 'unknown'; + if (isset($commentAttributes->Author)) { + $author = (string)$commentAttributes->Author; +// echo 'Author: ',$author,'
'; + } + $node = $cell->Comment->Data->asXML(); +// $annotation = str_replace('html:','',substr($node,49,-10)); +// echo $annotation,'
'; + $annotation = strip_tags($node); +// echo 'Annotation: ',$annotation,'
'; + $objPHPExcel->getActiveSheet()->getComment( $columnID.$rowID ) + ->setAuthor( $author ) + ->setText($this->_parseRichText($annotation) ); + } + + if (($cellIsSet) && (isset($cell_ss['StyleID']))) { + $style = (string) $cell_ss['StyleID']; +// echo 'Cell style for '.$columnID.$rowID.' is '.$style.'
'; + if ((isset($this->_styles[$style])) && (count($this->_styles[$style]) > 0)) { +// echo 'Cell '.$columnID.$rowID.'
'; +// print_r($this->_styles[$style]); +// echo '
'; + if (!$objPHPExcel->getActiveSheet()->cellExists($columnID.$rowID)) { + $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValue(NULL); + } + $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($this->_styles[$style]); + } + } + ++$columnID; + } + + if ($rowHasData) { + if (isset($row_ss['StyleID'])) { + $rowStyle = $row_ss['StyleID']; + } + if (isset($row_ss['Height'])) { + $rowHeight = $row_ss['Height']; +// echo 'Setting row height to '.$rowHeight.'
'; + $objPHPExcel->getActiveSheet()->getRowDimension($rowID)->setRowHeight($rowHeight); + } + } + + ++$rowID; + } } ++$worksheetID; } @@ -671,23 +776,12 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader return $objPHPExcel; } - /** - * Get sheet index - * - * @return int - */ - public function getSheetIndex() { - return $this->_sheetIndex; + private function _parseRichText($is = '') { + $value = new PHPExcel_RichText(); + + $value->createText($is); + + return $value; } - /** - * Set sheet index - * - * @param int $pValue Sheet index - * @return PHPExcel_Reader_Excel2003XML - */ - public function setSheetIndex($pValue = 0) { - $this->_sheetIndex = $pValue; - return $this; - } } diff --git a/libraries/PHPExcel/PHPExcel/Reader/Excel2007.php b/libraries/PHPExcel/PHPExcel/Reader/Excel2007.php index c4e3e412d..642abb1bd 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/Excel2007.php +++ b/libraries/PHPExcel/PHPExcel/Reader/Excel2007.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,34 +33,31 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** - * PHPExcel_Reader_Excel2007 + * PHPExcel_Reader_Excel2007 * - * @category PHPExcel - * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @category PHPExcel + * @package PHPExcel_Reader + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader { /** - * Read data only? + * Read data only? + * Identifies whether the Reader should only read data values for cells, and ignore any formatting information; + * or whether it should read both data and formatting * - * @var boolean + * @var boolean */ private $_readDataOnly = false; /** - * Restict which sheets should be loaded? + * Restrict which sheets should be loaded? + * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded. * - * @var array + * @var array of string */ private $_loadSheetsOnly = null; @@ -71,23 +68,40 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader */ private $_readFilter = null; - + /** + * PHPExcel_ReferenceHelper instance + * + * @var PHPExcel_ReferenceHelper + */ private $_referenceHelper = null; /** - * Read data only? + * PHPExcel_Reader_Excel2007_Theme instance * - * @return boolean + * @var PHPExcel_Reader_Excel2007_Theme + */ + private static $_theme = null; + + + /** + * Read data only? + * If this is true, then the Reader will only read data values for cells, it will not read any formatting information. + * If false (the default) it will read data and formatting. + * + * @return boolean */ public function getReadDataOnly() { return $this->_readDataOnly; } /** - * Set read data only + * Set read data only + * Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information. + * Set to false (the default) to advise the Reader to read both data and formatting for cells. * - * @param boolean $pValue - * @return PHPExcel_Reader_Excel2007 + * @param boolean $pValue + * + * @return PHPExcel_Reader_Excel2007 */ public function setReadDataOnly($pValue = false) { $this->_readDataOnly = $pValue; @@ -95,9 +109,11 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } /** - * Get which sheets to load + * Get which sheets to load + * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null + * indicating that all worksheets in the workbook should be loaded. * - * @return mixed + * @return mixed */ public function getLoadSheetsOnly() { @@ -105,10 +121,13 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } /** - * Set which sheets to load + * Set which sheets to load * - * @param mixed $value - * @return PHPExcel_Reader_Excel2007 + * @param mixed $value + * This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name. + * If NULL, then it tells the Reader to read all worksheets in the workbook + * + * @return PHPExcel_Reader_Excel2007 */ public function setLoadSheetsOnly($value = null) { @@ -118,9 +137,10 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } /** - * Set all sheets to load + * Set all sheets to load + * Tells the Reader to load all worksheets from the workbook. * - * @return PHPExcel_Reader_Excel2007 + * @return PHPExcel_Reader_Excel2007 */ public function setLoadAllSheets() { @@ -174,39 +194,47 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); } + $xl = false; // Load file $zip = new ZipArchive; if ($zip->open($pFilename) === true) { // check if it is an OOXML archive $rels = simplexml_load_string($this->_getFromZipArchive($zip, "_rels/.rels")); + foreach ($rels->Relationship as $rel) { + switch ($rel["Type"]) { + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument": + if (basename($rel["Target"]) == 'workbook.xml') { + $xl = true; + } + break; + } + } $zip->close(); - - return ($rels !== false); } - return false; + return $xl; } - private function _castToBool($c) { + private static function _castToBool($c) { // echo 'Initial Cast to Boolean
'; $value = isset($c->v) ? (string) $c->v : null; if ($value == '0') { - $value = false; + return false; } elseif ($value == '1') { - $value = true; + return true; } else { - $value = (bool)$c->v; + return (bool)$c->v; } return $value; } // function _castToBool() - private function _castToError($c) { + private static function _castToError($c) { // echo 'Initial Cast to Error
'; return isset($c->v) ? (string) $c->v : null;; } // function _castToError() - private function _castToString($c) { + private static function _castToString($c) { // echo 'Initial Cast to String
'; return isset($c->v) ? (string) $c->v : null;; } // function _castToString() @@ -216,7 +244,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader // echo '$c->f is '.$c->f.'
'; $cellDataType = 'f'; $value = "={$c->f}"; - $calculatedValue = $this->$castBaseType($c); + $calculatedValue = self::$castBaseType($c); // Shared formula? if (isset($c->f['t']) && strtolower((string)$c->f['t']) == 'shared') { @@ -275,17 +303,48 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader $contents = $archive->getFromName(substr($fileName, 1)); } - /* - if (strpos($contents, 'open($pFilename); + + $rels = simplexml_load_string($this->_getFromZipArchive($zip, "_rels/.rels")); //~ http://schemas.openxmlformats.org/package/2006/relationships"); + foreach ($rels->Relationship as $rel) { + switch ($rel["Type"]) { + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument": + $xmlWorkbook = simplexml_load_string($this->_getFromZipArchive($zip, "{$rel['Target']}")); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + + if ($xmlWorkbook->sheets) { + foreach ($xmlWorkbook->sheets->sheet as $eleSheet) { + // Check if sheet should be skipped + $worksheetNames[] = (string) $eleSheet["name"]; + } + } + } + } + + $zip->close(); + + return $worksheetNames; + } + + /** * Loads PHPExcel from file * @@ -309,6 +368,44 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader $zip = new ZipArchive; $zip->open($pFilename); + // Read the theme first, because we need the colour scheme when reading the styles + $wbRels = simplexml_load_string($this->_getFromZipArchive($zip, "xl/_rels/workbook.xml.rels")); //~ http://schemas.openxmlformats.org/package/2006/relationships"); + foreach ($wbRels->Relationship as $rel) { + switch ($rel["Type"]) { + case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme": + $themeOrderArray = array('lt1','dk1','lt2','dk2'); + $themeOrderAdditional = count($themeOrderArray); + + $xmlTheme = simplexml_load_string($this->_getFromZipArchive($zip, "xl/{$rel['Target']}")); + if (is_object($xmlTheme)) { + $xmlThemeName = $xmlTheme->attributes(); + $xmlTheme = $xmlTheme->children("http://schemas.openxmlformats.org/drawingml/2006/main"); + $themeName = (string)$xmlThemeName['name']; + + $colourScheme = $xmlTheme->themeElements->clrScheme->attributes(); + $colourSchemeName = (string)$colourScheme['name']; + $colourScheme = $xmlTheme->themeElements->clrScheme->children("http://schemas.openxmlformats.org/drawingml/2006/main"); + + $themeColours = array(); + foreach ($colourScheme as $k => $xmlColour) { + $themePos = array_search($k,$themeOrderArray); + if ($themePos === false) { + $themePos = $themeOrderAdditional++; + } + if (isset($xmlColour->sysClr)) { + $xmlColourData = $xmlColour->sysClr->attributes(); + $themeColours[$themePos] = $xmlColourData['lastClr']; + } elseif (isset($xmlColour->srgbClr)) { + $xmlColourData = $xmlColour->srgbClr->attributes(); + $themeColours[$themePos] = $xmlColourData['val']; + } + } + self::$_theme = new PHPExcel_Reader_Excel2007_Theme($themeName,$colourSchemeName,$themeColours); + } + break; + } + } + $rels = simplexml_load_string($this->_getFromZipArchive($zip, "_rels/.rels")); //~ http://schemas.openxmlformats.org/package/2006/relationships"); foreach ($rels->Relationship as $rel) { switch ($rel["Type"]) { @@ -345,8 +442,19 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties": $xmlCore = simplexml_load_string($this->_getFromZipArchive($zip, "{$rel['Target']}")); if (is_object($xmlCore)) { - $xmlCore->registerXPathNamespace("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); $docProps = $excel->getProperties(); + foreach ($xmlCore as $xmlProperty) { + $cellDataOfficeAttributes = $xmlProperty->attributes(); + if (isset($cellDataOfficeAttributes['name'])) { + $propertyName = (string) $cellDataOfficeAttributes['name']; + $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); + $attributeType = $cellDataOfficeChildren->getName(); + $attributeValue = (string) $cellDataOfficeChildren->{$attributeType}; + $attributeValue = PHPExcel_DocumentProperties::convertProperty($attributeValue,$attributeType); + $attributeType = PHPExcel_DocumentProperties::convertPropertyType($attributeType); + $docProps->setCustomProperty($propertyName,$attributeValue,$attributeType); + } + } } break; @@ -418,7 +526,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader // add style to cellXf collection $objStyle = new PHPExcel_Style; - $this->_readStyle($objStyle, $style); + self::_readStyle($objStyle, $style); $excel->addCellXf($objStyle); } @@ -445,7 +553,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader // add style to cellStyleXf collection $objStyle = new PHPExcel_Style; - $this->_readStyle($objStyle, $cellStyle); + self::_readStyle($objStyle, $cellStyle); $excel->addCellStyleXf($objStyle); } } @@ -455,7 +563,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader if ($xmlStyles->dxfs) { foreach ($xmlStyles->dxfs->dxf as $dxf) { $style = new PHPExcel_Style; - $this->_readStyle($style, $dxf); + self::_readStyle($style, $dxf); $dxfs[] = $style; } } @@ -467,7 +575,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader if (isset($cellStyles[intval($cellStyle['xfId'])])) { // Set default style $style = new PHPExcel_Style; - $this->_readStyle($style, $cellStyles[intval($cellStyle['xfId'])]); + self::_readStyle($style, $cellStyles[intval($cellStyle['xfId'])]); // normal style, currently not using it for anything } @@ -710,7 +818,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader case "b": // echo 'Boolean
'; if (!isset($c->f)) { - $value = $this->_castToBool($c); + $value = self::_castToBool($c); } else { // Formula $this->_castToFormula($c,$r,$cellDataType,$value,$calculatedValue,$sharedFormulas,'_castToBool'); @@ -730,7 +838,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader case "e": // echo 'Error
'; if (!isset($c->f)) { - $value = $this->_castToError($c); + $value = self::_castToError($c); } else { // Formula $this->_castToFormula($c,$r,$cellDataType,$value,$calculatedValue,$sharedFormulas,'_castToError'); @@ -743,7 +851,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader // echo 'Default
'; if (!isset($c->f)) { // echo 'Not a Formula
'; - $value = $this->_castToString($c); + $value = self::_castToString($c); } else { // echo 'Treat as Formula
'; // Formula @@ -1267,7 +1375,11 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader // Extract range $extractedRange = (string)$definedName; $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange); - $extractedRange = str_replace('$', '', $extractedRange); + if (($spos = strpos($extractedRange,'!')) !== false) { + $extractedRange = substr($extractedRange,0,$spos).str_replace('$', '', substr($extractedRange,$spos)); + } else { + $extractedRange = str_replace('$', '', $extractedRange); + } // Valid range? if (stripos((string)$definedName, '#REF!') !== false || $extractedRange == '') { @@ -1330,7 +1442,11 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader // Extract range $extractedRange = (string)$definedName; $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange); - $extractedRange = str_replace('$', '', $extractedRange); + if (($spos = strpos($extractedRange,'!')) !== false) { + $extractedRange = substr($extractedRange,0,$spos).str_replace('$', '', substr($extractedRange,$spos)); + } else { + $extractedRange = str_replace('$', '', $extractedRange); + } // Valid range? if (stripos((string)$definedName, '#REF!') !== false || $extractedRange == '') { @@ -1407,18 +1523,34 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } + $zip->close(); + return $excel; } - private function _readColor($color) { + private static function _readColor($color, $background=false) { if (isset($color["rgb"])) { return (string)$color["rgb"]; } else if (isset($color["indexed"])) { - return PHPExcel_Style_Color::indexedColor($color["indexed"])->getARGB(); + return PHPExcel_Style_Color::indexedColor($color["indexed"],$background)->getARGB(); + } else if (isset($color["theme"])) { + if (!is_null(self::$_theme)) { + $returnColour = self::$_theme->getColourByIndex((int)$color["theme"]); + if (isset($color["tint"])) { + $tintAdjust = (float) $color["tint"]; + $returnColour = PHPExcel_Style_Color::changeBrightness($returnColour, $tintAdjust); + } + return 'FF'.$returnColour; + } } + + if ($background) { + return 'FFFFFFFF'; + } + return 'FF000000'; } - private function _readStyle($docStyle, $style) { + private static function _readStyle($docStyle, $style) { // format code if (isset($style->numFmt)) { $docStyle->getNumberFormat()->setFormatCode($style->numFmt); @@ -1437,7 +1569,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader if (isset($style->font->strike)) { $docStyle->getFont()->setStrikethrough(!isset($style->font->strike["val"]) || $style->font->strike["val"] == 'true' || $style->font->strike["val"] == '1'); } - $docStyle->getFont()->getColor()->setARGB($this->_readColor($style->font->color)); + $docStyle->getFont()->getColor()->setARGB(self::_readColor($style->font->color)); if (isset($style->font->u) && !isset($style->font->u["val"])) { $docStyle->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE); @@ -1460,21 +1592,23 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader if (isset($style->fill)) { if ($style->fill->gradientFill) { $gradientFill = $style->fill->gradientFill[0]; - $docStyle->getFill()->setFillType((string) $gradientFill["type"]); + if(!empty($gradientFill["type"])) { + $docStyle->getFill()->setFillType((string) $gradientFill["type"]); + } $docStyle->getFill()->setRotation(floatval($gradientFill["degree"])); $gradientFill->registerXPathNamespace("sml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"); - $docStyle->getFill()->getStartColor()->setARGB($this->_readColor( self::array_item($gradientFill->xpath("sml:stop[@position=0]"))->color) ); - $docStyle->getFill()->getEndColor()->setARGB($this->_readColor( self::array_item($gradientFill->xpath("sml:stop[@position=1]"))->color) ); + $docStyle->getFill()->getStartColor()->setARGB(self::_readColor( self::array_item($gradientFill->xpath("sml:stop[@position=0]"))->color) ); + $docStyle->getFill()->getEndColor()->setARGB(self::_readColor( self::array_item($gradientFill->xpath("sml:stop[@position=1]"))->color) ); } elseif ($style->fill->patternFill) { $patternType = (string)$style->fill->patternFill["patternType"] != '' ? (string)$style->fill->patternFill["patternType"] : 'solid'; $docStyle->getFill()->setFillType($patternType); if ($style->fill->patternFill->fgColor) { - $docStyle->getFill()->getStartColor()->setARGB($this->_readColor($style->fill->patternFill->fgColor)); + $docStyle->getFill()->getStartColor()->setARGB(self::_readColor($style->fill->patternFill->fgColor,true)); } else { $docStyle->getFill()->getStartColor()->setARGB('FF000000'); } if ($style->fill->patternFill->bgColor) { - $docStyle->getFill()->getEndColor()->setARGB($this->_readColor($style->fill->patternFill->bgColor)); + $docStyle->getFill()->getEndColor()->setARGB(self::_readColor($style->fill->patternFill->bgColor,true)); } } } @@ -1498,11 +1632,11 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } elseif ($diagonalUp == true && $diagonalDown == true) { $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH); } - $this->_readBorder($docStyle->getBorders()->getLeft(), $style->border->left); - $this->_readBorder($docStyle->getBorders()->getRight(), $style->border->right); - $this->_readBorder($docStyle->getBorders()->getTop(), $style->border->top); - $this->_readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom); - $this->_readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal); + self::_readBorder($docStyle->getBorders()->getLeft(), $style->border->left); + self::_readBorder($docStyle->getBorders()->getRight(), $style->border->right); + self::_readBorder($docStyle->getBorders()->getTop(), $style->border->top); + self::_readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom); + self::_readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal); } // alignment @@ -1543,12 +1677,12 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } } - private function _readBorder($docBorder, $eleBorder) { + private static function _readBorder($docBorder, $eleBorder) { if (isset($eleBorder["style"])) { $docBorder->setBorderStyle((string) $eleBorder["style"]); } if (isset($eleBorder->color)) { - $docBorder->getColor()->setARGB($this->_readColor($eleBorder->color)); + $docBorder->getColor()->setARGB(self::_readColor($eleBorder->color)); } } @@ -1574,7 +1708,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } if (isset($run->rPr->color)) { - $objText->getFont()->setColor( new PHPExcel_Style_Color( $this->_readColor($run->rPr->color) ) ); + $objText->getFont()->setColor( new PHPExcel_Style_Color( self::_readColor($run->rPr->color) ) ); } if ( (isset($run->rPr->b["val"]) && ((string) $run->rPr->b["val"] == 'true' || (string) $run->rPr->b["val"] == '1')) @@ -1623,11 +1757,9 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader } private static function toCSSArray($style) { - $style = str_replace("\r", "", $style); - $style = str_replace("\n", "", $style); + $style = str_replace(array("\r","\n"), "", $style); $temp = explode(';', $style); - $style = array(); foreach ($temp as $item) { $item = explode(':', $item); diff --git a/libraries/PHPExcel/PHPExcel/Reader/Excel2007/Theme.php b/libraries/PHPExcel/PHPExcel/Reader/Excel2007/Theme.php new file mode 100644 index 000000000..89e24ffea --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Reader/Excel2007/Theme.php @@ -0,0 +1,124 @@ +_themeName = $themeName; + $this->_colourSchemeName = $colourSchemeName; + $this->_colourMap = $colourMap; + } + + /** + * Get Theme Name + * + * @return string + */ + public function getThemeName() + { + return $this->_themeName; + } + + /** + * Get colour Scheme Name + * + * @return string + */ + public function getColourSchemeName() { + return $this->_colourSchemeName; + } + + /** + * Get colour Map Value by Position + * + * @return string + */ + public function getColourByIndex($index=0) { + if (isset($this->_colourMap[$index])) { + return $this->_colourMap[$index]; + } + return null; + } + + /** + * Implement PHP __clone to create a deep clone, not just a shallow copy. + */ + public function __clone() { + $vars = get_object_vars($this); + foreach ($vars as $key => $value) { + if ((is_object($value)) && ($key != '_parent')) { + $this->$key = clone $value; + } else { + $this->$key = $value; + } + } + } +} diff --git a/libraries/PHPExcel/PHPExcel/Reader/Excel5.php b/libraries/PHPExcel/PHPExcel/Reader/Excel5.php index 5c71ee8aa..327dc2949 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/Excel5.php +++ b/libraries/PHPExcel/PHPExcel/Reader/Excel5.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ // Original file header of ParseXL (used as the base for this class): @@ -64,22 +64,16 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** - * PHPExcel_Reader_Excel5 + * PHPExcel_Reader_Excel5 * - * This class uses {@link http://sourceforge.net/projects/phpexcelreader/parseXL} + * This class uses {@link http://sourceforge.net/projects/phpexcelreader/parseXL} * - * @category PHPExcel - * @package PHPExcel_Reader_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @category PHPExcel + * @package PHPExcel_Reader_Excel5 + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader { @@ -165,16 +159,19 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader const XLS_Type_UNKNOWN = 0xffff; /** - * Read data only? + * Read data only? + * Identifies whether the Reader should only read data values for cells, and ignore any formatting information; + * or whether it should read both data and formatting * - * @var boolean + * @var boolean */ private $_readDataOnly = false; /** - * Restict which sheets should be loaded? + * Restrict which sheets should be loaded? + * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded. * - * @var array + * @var array of string */ private $_loadSheetsOnly = null; @@ -192,6 +189,20 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private $_summaryInformation; + /** + * Extended Summary Information stream data. + * + * @var string + */ + private $_documentSummaryInformation; + + /** + * User-Defined Properties stream data. + * + * @var string + */ + private $_userDefinedProperties; + /** * Workbook stream data. (Includes workbook globals substream as well as sheet substreams) * @@ -326,6 +337,20 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private $_objs; + /** + * Text Objects. One TXO record corresponds with one entry. + * + * @var array + */ + private $_textObjects; + + /** + * Cell Annotations (BIFF8) + * + * @var array + */ + private $_cellNotes; + /** * The combined MSODRAWINGGROUP data * @@ -376,10 +401,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private $_sharedFormulaParts; + /** - * Read data only? + * Read data only? + * If this is true, then the Reader will only read data values for cells, it will not read any formatting information. + * If false (the default) it will read data and formatting. * - * @return boolean + * @return boolean */ public function getReadDataOnly() { @@ -387,10 +415,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } /** - * Set read data only + * Set read data only + * Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information. + * Set to false (the default) to advise the Reader to read both data and formatting for cells. * - * @param boolean $pValue - * @return PHPExcel_Reader_Excel5 + * @param boolean $pValue + * + * @return PHPExcel_Reader_Excel5 */ public function setReadDataOnly($pValue = false) { @@ -399,9 +430,11 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } /** - * Get which sheets to load + * Get which sheets to load + * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null + * indicating that all worksheets in the workbook should be loaded. * - * @return mixed + * @return mixed */ public function getLoadSheetsOnly() { @@ -409,10 +442,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } /** - * Set which sheets to load + * Set which sheets to load * - * @param mixed $value - * @return PHPExcel_Reader_Excel5 + * @param mixed $value + * This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name. + * If NULL, then it tells the Reader to read all worksheets in the workbook + * + * @return PHPExcel_Reader_Excel5 */ public function setLoadSheetsOnly($value = null) { @@ -422,9 +458,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } /** - * Set all sheets to load + * Set all sheets to load + * Tells the Reader to load all worksheets from the workbook. * - * @return PHPExcel_Reader_Excel5 + * @return PHPExcel_Reader_Excel5 */ public function setLoadAllSheets() { @@ -485,6 +522,55 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } } + /** + * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object + * + * @param string $pFilename + * @throws Exception + */ + public function listWorksheetNames($pFilename) + { + // Check if file exists + if (!file_exists($pFilename)) { + throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); + } + + $worksheetNames = array(); + + // Read the OLE file + $this->_loadOLE($pFilename); + + // total byte size of Excel data (workbook global substream + sheet substreams) + $this->_dataSize = strlen($this->_data); + + $this->_pos = 0; + $this->_sheets = array(); + + // Parse Workbook Global Substream + while ($this->_pos < $this->_dataSize) { + $code = self::_GetInt2d($this->_data, $this->_pos); + + switch ($code) { + case self::XLS_Type_BOF: $this->_readBof(); break; + case self::XLS_Type_SHEET: $this->_readSheet(); break; + case self::XLS_Type_EOF: $this->_readDefault(); break 2; + default: $this->_readDefault(); break; + } + } + + foreach ($this->_sheets as $sheet) { + if ($sheet['sheetType'] != 0x00) { + // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module + continue; + } + + $worksheetNames[] = $sheet['name']; + } + + return $worksheetNames; + } + + /** * Loads PHPExcel from file * @@ -508,6 +594,9 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // Read the summary information stream (containing meta data) $this->_readSummaryInformation(); + // Read the Additional document summary information stream (containing application-specific meta data) + $this->_readDocumentSummaryInformation(); + // total byte size of Excel data (workbook global substream + sheet substreams) $this->_dataSize = strlen($this->_data); @@ -529,7 +618,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // Parse Workbook Global Substream while ($this->_pos < $this->_dataSize) { - $code = $this->_GetInt2d($this->_data, $this->_pos); + $code = self::_GetInt2d($this->_data, $this->_pos); switch ($code) { case self::XLS_Type_BOF: $this->_readBof(); break; @@ -559,7 +648,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { foreach ($this->_objFonts as $objFont) { if (isset($objFont->colorIndex)) { - $color = $this->_readColor($objFont->colorIndex); + $color = self::_readColor($objFont->colorIndex,$this->_palette,$this->_version); $objFont->getColor()->setRGB($color['rgb']); } } @@ -569,12 +658,12 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $fill = $objStyle->getFill(); if (isset($fill->startcolorIndex)) { - $startColor = $this->_readColor($fill->startcolorIndex); + $startColor = self::_readColor($fill->startcolorIndex,$this->_palette,$this->_version); $fill->getStartColor()->setRGB($startColor['rgb']); } if (isset($fill->endcolorIndex)) { - $endColor = $this->_readColor($fill->endcolorIndex); + $endColor = self::_readColor($fill->endcolorIndex,$this->_palette,$this->_version); $fill->getEndColor()->setRGB($endColor['rgb']); } @@ -586,27 +675,27 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $diagonal = $objStyle->getBorders()->getDiagonal(); if (isset($top->colorIndex)) { - $borderTopColor = $this->_readColor($top->colorIndex); + $borderTopColor = self::_readColor($top->colorIndex,$this->_palette,$this->_version); $top->getColor()->setRGB($borderTopColor['rgb']); } if (isset($right->colorIndex)) { - $borderRightColor = $this->_readColor($right->colorIndex); + $borderRightColor = self::_readColor($right->colorIndex,$this->_palette,$this->_version); $right->getColor()->setRGB($borderRightColor['rgb']); } if (isset($bottom->colorIndex)) { - $borderBottomColor = $this->_readColor($bottom->colorIndex); + $borderBottomColor = self::_readColor($bottom->colorIndex,$this->_palette,$this->_version); $bottom->getColor()->setRGB($borderBottomColor['rgb']); } if (isset($left->colorIndex)) { - $borderLeftColor = $this->_readColor($left->colorIndex); + $borderLeftColor = self::_readColor($left->colorIndex,$this->_palette,$this->_version); $left->getColor()->setRGB($borderLeftColor['rgb']); } if (isset($diagonal->colorIndex)) { - $borderDiagonalColor = $this->_readColor($diagonal->colorIndex); + $borderDiagonalColor = self::_readColor($diagonal->colorIndex,$this->_palette,$this->_version); $diagonal->getColor()->setRGB($borderDiagonalColor['rgb']); } } @@ -658,8 +747,15 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // Initialize shared formulas $this->_sharedFormulas = array(); + // Initialize text objs + $this->_textObjects = array(); + + // Initialize cell annotations + $this->_cellNotes = array(); + $this->textObjRef = -1; + while ($this->_pos <= $this->_dataSize - 4) { - $code = $this->_GetInt2d($this->_data, $this->_pos); + $code = self::_GetInt2d($this->_data, $this->_pos); switch ($code) { case self::XLS_Type_BOF: $this->_readBof(); break; @@ -709,7 +805,9 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader case self::XLS_Type_SHEETLAYOUT: $this->_readSheetLayout(); break; case self::XLS_Type_SHEETPROTECTION: $this->_readSheetProtection(); break; case self::XLS_Type_RANGEPROTECTION: $this->_readRangeProtection(); break; + case self::XLS_Type_NOTE: $this->_readNote(); break; //case self::XLS_Type_IMDATA: $this->_readImData(); break; + case self::XLS_Type_TXO: $this->_readTextObject(); break; case self::XLS_Type_CONTINUE: $this->_readContinue(); break; case self::XLS_Type_EOF: $this->_readDefault(); break 2; default: $this->_readDefault(); break; @@ -733,6 +831,9 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // treat OBJ records foreach ($this->_objs as $n => $obj) { +// echo '
Object reference is ',$n,'
'; +// var_dump($obj); +// echo '
'; // the first shape container never has a corresponding OBJ record, hence $n + 1 $spContainer = $allSpContainers[$n + 1]; @@ -758,9 +859,35 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->_phpSheet, $startColumn) / 1024; $offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet, $startRow) / 256; - switch ($obj['type']) { + switch ($obj['otObjType']) { + + case 0x19: + // Note +// echo 'Cell Annotation Object
'; +// echo 'Object ID is ',$obj['idObjID'],'
'; +// + if (isset($this->_cellNotes[$obj['idObjID']])) { + $cellNote = $this->_cellNotes[$obj['idObjID']]; + +// echo '_cellNotes[',$obj['idObjID'],']: '; +// var_dump($cellNote); +// echo '
'; +// + if (isset($this->_textObjects[$obj['idObjID']])) { + $textObject = $this->_textObjects[$obj['idObjID']]; +// echo '_textObject: '; +// var_dump($textObject); +// echo '
'; +// + $this->_cellNotes[$obj['idObjID']]['objTextData'] = $textObject; + $text = $textObject['text']; + } +// echo $text,'
'; + } + break; case 0x08: +// echo 'Picture Object
'; // picture // get index to BSE entry (1-based) @@ -783,16 +910,15 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $drawing->setOffsetY($offsetY); switch ($blipType) { + case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG: + $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG); + $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG); + break; - case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG: - $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG); - $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG); - break; - - case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG: - $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG); - $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG); - break; + case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG: + $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG); + $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG); + break; } $drawing->setWorksheet($this->_phpSheet); @@ -811,8 +937,23 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // treat SHAREDFMLA records if ($this->_version == self::XLS_BIFF8) { foreach ($this->_sharedFormulaParts as $cell => $baseCell) { - $formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell); - $this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA); + list($column, $row) = PHPExcel_Cell::coordinateFromString($cell); + if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle()) ) { + $formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell); + $this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA); + } + } + } + + if (count($this->_cellNotes) > 0) { + foreach($this->_cellNotes as $note => $noteDetails) { +// echo 'Cell annotation ',$note,'
'; +// var_dump($noteDetails); +// echo '
'; + $cellAddress = str_replace('$','',$noteDetails['cellRef']); + $this->_phpSheet->getComment( $cellAddress ) + ->setAuthor( $noteDetails['author'] ) + ->setText($this->_parseRichText($noteDetails['objTextData']['text']) ); } } } @@ -924,12 +1065,19 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // OLE reader $ole = new PHPExcel_Shared_OLERead(); - // get excel data + // get excel data, $res = $ole->read($pFilename); - $this->_data = $ole->getWorkBook(); + // Get workbook data: workbook stream + sheet streams + $this->_data = $ole->getStream($ole->wrkbook); // Get summary information data - $this->_summaryInformation = $ole->getSummaryInformation(); + $this->_summaryInformation = $ole->getStream($ole->summaryInformation); + + // Get additional document summary information data + $this->_documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation); + + // Get user-defined property data +// $this->_userDefinedProperties = $ole->getUserDefinedProperties(); } /** @@ -947,31 +1095,34 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 6; size: 2; OS indicator // offset: 8; size: 16 // offset: 24; size: 4; section count + $secCount = self::_GetInt4d($this->_summaryInformation, 24); // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9 // offset: 44; size: 4 + $secOffset = self::_GetInt4d($this->_summaryInformation, 44); // section header - // offset: 48; size: 4; section length - $secLength = $this->_GetInt4d($this->_summaryInformation, 48); + // offset: $secOffset; size: 4; section length + $secLength = self::_GetInt4d($this->_summaryInformation, $secOffset); - // offset: 52; size: 4; property count - $countProperties = $this->_GetInt4d($this->_summaryInformation, 52); + // offset: $secOffset+4; size: 4; property count + $countProperties = self::_GetInt4d($this->_summaryInformation, $secOffset+4); // initialize code page (used to resolve string values) $codePage = 'CP1252'; - // offset: 56; size: var + // offset: ($secOffset+8); size: var // loop through property decarations and properties for ($i = 0; $i < $countProperties; ++$i) { - // offset: 56 + 8 * $i; size: 4; property ID - $id = $this->_GetInt4d($this->_summaryInformation, 56 + 8 * $i); + // offset: ($secOffset+8) + (8 * $i); size: 4; property ID + $id = self::_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i)); - // offset: 60 + 8 * $i; size: 4; offset from beginning of section (48) - $offset = $this->_GetInt4d($this->_summaryInformation, 60 + 8 * $i); + // Use value of property id as appropriate + // offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48) + $offset = self::_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i)); - $type = $this->_GetInt4d($this->_summaryInformation, 48 + $offset); + $type = self::_GetInt4d($this->_summaryInformation, $secOffset + $offset); // initialize property value $value = null; @@ -979,11 +1130,11 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // extract property value based on property type switch ($type) { case 0x02: // 2 byte signed integer - $value = $this->_GetInt2d($this->_summaryInformation, 52 + $offset); + $value = self::_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset); break; case 0x03: // 4 byte signed integer - $value = $this->_GetInt4d($this->_summaryInformation, 52 + $offset); + $value = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset); break; case 0x13: // 4 byte unsigned integer @@ -991,15 +1142,15 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 0x1E: // null-terminated string prepended by dword string length - $byteLength = $this->_GetInt4d($this->_summaryInformation, 52 + $offset); - $value = substr($this->_summaryInformation, 56 + $offset, $byteLength); + $byteLength = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset); + $value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength); $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage); $value = rtrim($value); break; case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601) // PHP-time - $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, 52 + $offset, 8)); + $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8)); break; case 0x47: // Clipboard format @@ -1007,51 +1158,236 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; } - // Use value of property id as appropriate switch ($id) { - case 0x01: // Code Page + case 0x01: // Code Page $codePage = PHPExcel_Shared_CodePage::NumberToName($value); break; - case 0x02: // Title + case 0x02: // Title $this->_phpExcel->getProperties()->setTitle($value); break; - case 0x03: // Subject + case 0x03: // Subject $this->_phpExcel->getProperties()->setSubject($value); break; - case 0x04: // Author (Creator) + case 0x04: // Author (Creator) $this->_phpExcel->getProperties()->setCreator($value); break; - case 0x05: // Keywords + case 0x05: // Keywords $this->_phpExcel->getProperties()->setKeywords($value); break; - case 0x06: // Comments (Description) + case 0x06: // Comments (Description) $this->_phpExcel->getProperties()->setDescription($value); break; - case 0x08: // Last Saved By (LastModifiedBy) + case 0x07: // Template + // Not supported by PHPExcel + break; + + case 0x08: // Last Saved By (LastModifiedBy) $this->_phpExcel->getProperties()->setLastModifiedBy($value); break; - case 0x09: // Revision - // not supported by PHPExcel + case 0x09: // Revision + // Not supported by PHPExcel break; - case 0x0C: // Created + case 0x0A: // Total Editing Time + // Not supported by PHPExcel + break; + + case 0x0B: // Last Printed + // Not supported by PHPExcel + break; + + case 0x0C: // Created Date/Time $this->_phpExcel->getProperties()->setCreated($value); break; - case 0x0D: // Modified + case 0x0D: // Modified Date/Time $this->_phpExcel->getProperties()->setModified($value); break; - case 0x12: // Name of creating application - // not supported by PHPExcel + case 0x0E: // Number of Pages + // Not supported by PHPExcel break; + + case 0x0F: // Number of Words + // Not supported by PHPExcel + break; + + case 0x10: // Number of Characters + // Not supported by PHPExcel + break; + + case 0x11: // Thumbnail + // Not supported by PHPExcel + break; + + case 0x12: // Name of creating application + // Not supported by PHPExcel + break; + + case 0x13: // Security + // Not supported by PHPExcel + break; + + } + } + } + + /** + * Read additional document summary information + */ + private function _readDocumentSummaryInformation() + { + if (!isset($this->_documentSummaryInformation)) { + return; + } + + // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark) + // offset: 2; size: 2; + // offset: 4; size: 2; OS version + // offset: 6; size: 2; OS indicator + // offset: 8; size: 16 + // offset: 24; size: 4; section count + $secCount = self::_GetInt4d($this->_documentSummaryInformation, 24); +// echo '$secCount = ',$secCount,'
'; + + // offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae + // offset: 44; size: 4; first section offset + $secOffset = self::_GetInt4d($this->_documentSummaryInformation, 44); +// echo '$secOffset = ',$secOffset,'
'; + + // section header + // offset: $secOffset; size: 4; section length + $secLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset); +// echo '$secLength = ',$secLength,'
'; + + // offset: $secOffset+4; size: 4; property count + $countProperties = self::_GetInt4d($this->_documentSummaryInformation, $secOffset+4); +// echo '$countProperties = ',$countProperties,'
'; + + // initialize code page (used to resolve string values) + $codePage = 'CP1252'; + + // offset: ($secOffset+8); size: var + // loop through property decarations and properties + for ($i = 0; $i < $countProperties; ++$i) { +// echo 'Property ',$i,'
'; + // offset: ($secOffset+8) + (8 * $i); size: 4; property ID + $id = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i)); +// echo 'ID is ',$id,'
'; + + // Use value of property id as appropriate + // offset: 60 + 8 * $i; size: 4; offset from beginning of section (48) + $offset = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i)); + + $type = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset); +// echo 'Type is ',$type,', '; + + // initialize property value + $value = null; + + // extract property value based on property type + switch ($type) { + case 0x02: // 2 byte signed integer + $value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset); + break; + + case 0x03: // 4 byte signed integer + $value = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset); + break; + + case 0x13: // 4 byte unsigned integer + // not needed yet, fix later if necessary + break; + + case 0x1E: // null-terminated string prepended by dword string length + $byteLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset); + $value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength); + $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage); + $value = rtrim($value); + break; + + case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601) + // PHP-Time + $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8)); + break; + + case 0x47: // Clipboard format + // not needed yet, fix later if necessary + break; + } + + switch ($id) { + case 0x01: // Code Page + $codePage = PHPExcel_Shared_CodePage::NumberToName($value); + break; + + case 0x02: // Category + $this->_phpExcel->getProperties()->setCategory($value); + break; + + case 0x03: // Presentation Target + // Not supported by PHPExcel + break; + + case 0x04: // Bytes + // Not supported by PHPExcel + break; + + case 0x05: // Lines + // Not supported by PHPExcel + break; + + case 0x06: // Paragraphs + // Not supported by PHPExcel + break; + + case 0x07: // Slides + // Not supported by PHPExcel + break; + + case 0x08: // Notes + // Not supported by PHPExcel + break; + + case 0x09: // Hidden Slides + // Not supported by PHPExcel + break; + + case 0x0A: // MM Clips + // Not supported by PHPExcel + break; + + case 0x0B: // Scale Crop + // Not supported by PHPExcel + break; + + case 0x0C: // Heading Pairs + // Not supported by PHPExcel + break; + + case 0x0D: // Titles of Parts + // Not supported by PHPExcel + break; + + case 0x0E: // Manager + $this->_phpExcel->getProperties()->setManager($value); + break; + + case 0x0F: // Company + $this->_phpExcel->getProperties()->setCompany($value); + break; + + case 0x10: // Links up-to-date + // Not supported by PHPExcel + break; + } } } @@ -1061,11 +1397,114 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readDefault() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); +// $recordData = substr($this->_data, $this->_pos + 4, $length); + + // move stream pointer to next record + $this->_pos += 4 + $length; + } + + + /** + * The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions, + * this record stores a note (cell note). This feature was significantly enhanced in Excel 97. + */ + private function _readNote() + { +// echo 'Read Cell Annotation
'; + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; + + if ($this->_readDataOnly) { + return; + } + + $cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4)); + if ($this->_version == self::XLS_BIFF8) { + $noteObjID = self::_GetInt2d($recordData, 6); + $noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8)); + $noteAuthor = $noteAuthor['value']; +// echo 'Note Address=',$cellAddress,'
'; +// echo 'Note Object ID=',$noteObjID,'
'; +// echo 'Note Author=',$noteAuthor,'
'; +// + $this->_cellNotes[$noteObjID] = array('cellRef' => $cellAddress, + 'objectID' => $noteObjID, + 'author' => $noteAuthor + ); + } else { + $extension = false; + if ($cellAddress == '$B$65536') { + // If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation + // note from the previous cell annotation. We're not yet handling this, so annotations longer than the + // max 2048 bytes will probably throw a wobbly. + $row = self::_GetInt2d($recordData, 0); + $extension = true; + $cellAddress = array_pop(array_keys($this->_phpSheet->getComments())); + } +// echo 'Note Address=',$cellAddress,'
'; + + $cellAddress = str_replace('$','',$cellAddress); + $noteLength = self::_GetInt2d($recordData, 4); + $noteText = trim(substr($recordData, 6)); +// echo 'Note Length=',$noteLength,'
'; +// echo 'Note Text=',$noteText,'
'; + + if ($extension) { + // Concatenate this extension with the currently set comment for the cell + $comment = $this->_phpSheet->getComment( $cellAddress ); + $commentText = $comment->getText()->getPlainText(); + $comment->setText($this->_parseRichText($commentText.$noteText) ); + } else { + // Set comment for the cell + $this->_phpSheet->getComment( $cellAddress ) +// ->setAuthor( $author ) + ->setText($this->_parseRichText($noteText) ); + } + } + + } + + /** + * The TEXT Object record contains the text associated with a cell annotation. + */ + private function _readTextObject() + { + $length = self::_GetInt2d($this->_data, $this->_pos + 2); + $recordData = substr($this->_data, $this->_pos + 4, $length); + + // move stream pointer to next record + $this->_pos += 4 + $length; + + if ($this->_readDataOnly) { + return; + } + + // recordData consists of an array of subrecords looking like this: + // grbit: 2 bytes; Option Flags + // rot: 2 bytes; rotation + // cchText: 2 bytes; length of the text (in the first continue record) + // cbRuns: 2 bytes; length of the formatting (in the second continue record) + // followed by the continuation records containing the actual text and formatting + $grbitOpts = self::_GetInt2d($recordData, 0); + $rot = self::_GetInt2d($recordData, 2); + $cchText = self::_GetInt2d($recordData, 10); + $cbRuns = self::_GetInt2d($recordData, 12); + $text = $this->_getSplicedRecordData(); + + $this->_textObjects[$this->textObjRef] = array( + 'text' => substr($text["recordData"],$text["spliceOffsets"][0]+1,$cchText), + 'format' => substr($text["recordData"],$text["spliceOffsets"][1],$cbRuns), + 'alignment' => $grbitOpts, + 'rotation' => $rot + ); + +// echo '_readTextObject()
'; +// var_dump($this->_textObjects[$this->textObjRef]); +// echo '
'; } /** @@ -1073,18 +1512,18 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readBof() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 2; size: 2; type of the following data - $substreamType = $this->_GetInt2d($recordData, 2); + $substreamType = self::_GetInt2d($recordData, 2); switch ($substreamType) { case self::XLS_WorkbookGlobals: - $version = $this->_GetInt2d($recordData, 0); + $version = self::_GetInt2d($recordData, 0); if (($version != self::XLS_BIFF8) && ($version != self::XLS_BIFF7)) { throw new Exception('Cannot read this Excel file. Version is too old.'); } @@ -1100,7 +1539,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // substream, e.g. chart // just skip the entire substream do { - $code = $this->_GetInt2d($this->_data, $this->_pos); + $code = self::_GetInt2d($this->_data, $this->_pos); $this->_readDefault(); } while ($code != self::XLS_Type_EOF && $this->_pos < $this->_dataSize); break; @@ -1120,8 +1559,8 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readFilepass() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); - $recordData = substr($this->_data, $this->_pos + 4, $length); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); +// $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; @@ -1140,14 +1579,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readCodepage() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; code page identifier - $codepage = $this->_GetInt2d($recordData, 0); + $codepage = self::_GetInt2d($recordData, 0); $this->_codepage = PHPExcel_Shared_CodePage::NumberToName($codepage); } @@ -1166,7 +1605,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readDateMode() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1184,7 +1623,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readFont() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1194,26 +1633,26 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $objFont = new PHPExcel_Style_Font(); // offset: 0; size: 2; height of the font (in twips = 1/20 of a point) - $size = $this->_GetInt2d($recordData, 0); + $size = self::_GetInt2d($recordData, 0); $objFont->setSize($size / 20); // offset: 2; size: 2; option flags // bit: 0; mask 0x0001; bold (redundant in BIFF5-BIFF8) // bit: 1; mask 0x0002; italic - $isItalic = (0x0002 & $this->_GetInt2d($recordData, 2)) >> 1; + $isItalic = (0x0002 & self::_GetInt2d($recordData, 2)) >> 1; if ($isItalic) $objFont->setItalic(true); // bit: 2; mask 0x0004; underlined (redundant in BIFF5-BIFF8) // bit: 3; mask 0x0008; strike - $isStrike = (0x0008 & $this->_GetInt2d($recordData, 2)) >> 3; + $isStrike = (0x0008 & self::_GetInt2d($recordData, 2)) >> 3; if ($isStrike) $objFont->setStrikethrough(true); // offset: 4; size: 2; colour index - $colorIndex = $this->_GetInt2d($recordData, 4); + $colorIndex = self::_GetInt2d($recordData, 4); $objFont->colorIndex = $colorIndex; // offset: 6; size: 2; font weight - $weight = $this->_GetInt2d($recordData, 6); + $weight = self::_GetInt2d($recordData, 6); switch ($weight) { case 0x02BC: $objFont->setBold(true); @@ -1221,7 +1660,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // offset: 8; size: 2; escapement type - $escapement = $this->_GetInt2d($recordData, 8); + $escapement = self::_GetInt2d($recordData, 8); switch ($escapement) { case 0x0001: $objFont->setSuperScript(true); @@ -1255,7 +1694,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 13; size: 1; not used // offset: 14; size: var; font name if ($this->_version == self::XLS_BIFF8) { - $string = $this->_readUnicodeStringShort(substr($recordData, 14)); + $string = self::_readUnicodeStringShort(substr($recordData, 14)); } else { $string = $this->_readByteStringShort(substr($recordData, 14)); } @@ -1281,17 +1720,17 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readFormat() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; if (!$this->_readDataOnly) { - $indexCode = $this->_GetInt2d($recordData, 0); + $indexCode = self::_GetInt2d($recordData, 0); if ($this->_version == self::XLS_BIFF8) { - $string = $this->_readUnicodeStringLong(substr($recordData, 2)); + $string = self::_readUnicodeStringLong(substr($recordData, 2)); } else { // BIFF7 $string = $this->_readByteStringShort(substr($recordData, 2)); @@ -1318,7 +1757,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readXf() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1328,17 +1767,17 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; Index to FONT record - if ($this->_GetInt2d($recordData, 0) < 4) { - $fontIndex = $this->_GetInt2d($recordData, 0); + if (self::_GetInt2d($recordData, 0) < 4) { + $fontIndex = self::_GetInt2d($recordData, 0); } else { // this has to do with that index 4 is omitted in all BIFF versions for some strange reason // check the OpenOffice documentation of the FONT record - $fontIndex = $this->_GetInt2d($recordData, 0) - 1; + $fontIndex = self::_GetInt2d($recordData, 0) - 1; } $objStyle->setFont($this->_objFonts[$fontIndex]); // offset: 2; size: 2; Index to FORMAT record - $numberFormatIndex = $this->_GetInt2d($recordData, 2); + $numberFormatIndex = self::_GetInt2d($recordData, 2); if (isset($this->_formats[$numberFormatIndex])) { // then we have user-defined format code $numberformat = array('code' => $this->_formats[$numberFormatIndex]); @@ -1353,7 +1792,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 4; size: 2; XF type, cell protection, and parent style XF // bit 2-0; mask 0x0007; XF_TYPE_PROT - $xfTypeProt = $this->_GetInt2d($recordData, 4); + $xfTypeProt = self::_GetInt2d($recordData, 4); // bit 0; mask 0x01; 1 = cell is locked $isLocked = (0x01 & $xfTypeProt) >> 0; $objStyle->getProtection()->setLocked($isLocked ? @@ -1450,33 +1889,33 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 10; size: 4; Cell border lines and background area // bit: 3-0; mask: 0x0000000F; left style - if ($bordersLeftStyle = $this->_mapBorderStyle((0x0000000F & $this->_GetInt4d($recordData, 10)) >> 0)) { + if ($bordersLeftStyle = self::_mapBorderStyle((0x0000000F & self::_GetInt4d($recordData, 10)) >> 0)) { $objStyle->getBorders()->getLeft()->setBorderStyle($bordersLeftStyle); } // bit: 7-4; mask: 0x000000F0; right style - if ($bordersRightStyle = $this->_mapBorderStyle((0x000000F0 & $this->_GetInt4d($recordData, 10)) >> 4)) { + if ($bordersRightStyle = self::_mapBorderStyle((0x000000F0 & self::_GetInt4d($recordData, 10)) >> 4)) { $objStyle->getBorders()->getRight()->setBorderStyle($bordersRightStyle); } // bit: 11-8; mask: 0x00000F00; top style - if ($bordersTopStyle = $this->_mapBorderStyle((0x00000F00 & $this->_GetInt4d($recordData, 10)) >> 8)) { + if ($bordersTopStyle = self::_mapBorderStyle((0x00000F00 & self::_GetInt4d($recordData, 10)) >> 8)) { $objStyle->getBorders()->getTop()->setBorderStyle($bordersTopStyle); } // bit: 15-12; mask: 0x0000F000; bottom style - if ($bordersBottomStyle = $this->_mapBorderStyle((0x0000F000 & $this->_GetInt4d($recordData, 10)) >> 12)) { + if ($bordersBottomStyle = self::_mapBorderStyle((0x0000F000 & self::_GetInt4d($recordData, 10)) >> 12)) { $objStyle->getBorders()->getBottom()->setBorderStyle($bordersBottomStyle); } // bit: 22-16; mask: 0x007F0000; left color - $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & $this->_GetInt4d($recordData, 10)) >> 16; + $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & self::_GetInt4d($recordData, 10)) >> 16; // bit: 29-23; mask: 0x3F800000; right color - $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & $this->_GetInt4d($recordData, 10)) >> 23; + $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & self::_GetInt4d($recordData, 10)) >> 23; // bit: 30; mask: 0x40000000; 1 = diagonal line from top left to right bottom - $diagonalDown = (0x40000000 & $this->_GetInt4d($recordData, 10)) >> 30 ? + $diagonalDown = (0x40000000 & self::_GetInt4d($recordData, 10)) >> 30 ? true : false; // bit: 31; mask: 0x80000000; 1 = diagonal line from bottom left to top right - $diagonalUp = (0x80000000 & $this->_GetInt4d($recordData, 10)) >> 31 ? + $diagonalUp = (0x80000000 & self::_GetInt4d($recordData, 10)) >> 31 ? true : false; if ($diagonalUp == false && $diagonalDown == false) { @@ -1491,29 +1930,29 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 14; size: 4; // bit: 6-0; mask: 0x0000007F; top color - $objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & $this->_GetInt4d($recordData, 14)) >> 0; + $objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & self::_GetInt4d($recordData, 14)) >> 0; // bit: 13-7; mask: 0x00003F80; bottom color - $objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & $this->_GetInt4d($recordData, 14)) >> 7; + $objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & self::_GetInt4d($recordData, 14)) >> 7; // bit: 20-14; mask: 0x001FC000; diagonal color - $objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & $this->_GetInt4d($recordData, 14)) >> 14; + $objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & self::_GetInt4d($recordData, 14)) >> 14; // bit: 24-21; mask: 0x01E00000; diagonal style - if ($bordersDiagonalStyle = $this->_mapBorderStyle((0x01E00000 & $this->_GetInt4d($recordData, 14)) >> 21)) { + if ($bordersDiagonalStyle = self::_mapBorderStyle((0x01E00000 & self::_GetInt4d($recordData, 14)) >> 21)) { $objStyle->getBorders()->getDiagonal()->setBorderStyle($bordersDiagonalStyle); } // bit: 31-26; mask: 0xFC000000 fill pattern - if ($fillType = $this->_mapFillPattern((0xFC000000 & $this->_GetInt4d($recordData, 14)) >> 26)) { + if ($fillType = self::_mapFillPattern((0xFC000000 & self::_GetInt4d($recordData, 14)) >> 26)) { $objStyle->getFill()->setFillType($fillType); } // offset: 18; size: 2; pattern and background colour // bit: 6-0; mask: 0x007F; color index for pattern color - $objStyle->getFill()->startcolorIndex = (0x007F & $this->_GetInt2d($recordData, 18)) >> 0; + $objStyle->getFill()->startcolorIndex = (0x007F & self::_GetInt2d($recordData, 18)) >> 0; // bit: 13-7; mask: 0x3F80; color index for pattern background - $objStyle->getFill()->endcolorIndex = (0x3F80 & $this->_GetInt2d($recordData, 18)) >> 7; + $objStyle->getFill()->endcolorIndex = (0x3F80 & self::_GetInt2d($recordData, 18)) >> 7; } else { // BIFF5 @@ -1538,7 +1977,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // offset: 8; size: 4; cell border lines and background area - $borderAndBackground = $this->_GetInt4d($recordData, 8); + $borderAndBackground = self::_GetInt4d($recordData, 8); // bit: 6-0; mask: 0x0000007F; color index for pattern color $objStyle->getFill()->startcolorIndex = (0x0000007F & $borderAndBackground) >> 0; @@ -1547,25 +1986,25 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $objStyle->getFill()->endcolorIndex = (0x00003F80 & $borderAndBackground) >> 7; // bit: 21-16; mask: 0x003F0000; fill pattern - $objStyle->getFill()->setFillType($this->_mapFillPattern((0x003F0000 & $borderAndBackground) >> 16)); + $objStyle->getFill()->setFillType(self::_mapFillPattern((0x003F0000 & $borderAndBackground) >> 16)); // bit: 24-22; mask: 0x01C00000; bottom line style - $objStyle->getBorders()->getBottom()->setBorderStyle($this->_mapBorderStyle((0x01C00000 & $borderAndBackground) >> 22)); + $objStyle->getBorders()->getBottom()->setBorderStyle(self::_mapBorderStyle((0x01C00000 & $borderAndBackground) >> 22)); // bit: 31-25; mask: 0xFE000000; bottom line color $objStyle->getBorders()->getBottom()->colorIndex = (0xFE000000 & $borderAndBackground) >> 25; // offset: 12; size: 4; cell border lines - $borderLines = $this->_GetInt4d($recordData, 12); + $borderLines = self::_GetInt4d($recordData, 12); // bit: 2-0; mask: 0x00000007; top line style - $objStyle->getBorders()->getTop()->setBorderStyle($this->_mapBorderStyle((0x00000007 & $borderLines) >> 0)); + $objStyle->getBorders()->getTop()->setBorderStyle(self::_mapBorderStyle((0x00000007 & $borderLines) >> 0)); // bit: 5-3; mask: 0x00000038; left line style - $objStyle->getBorders()->getLeft()->setBorderStyle($this->_mapBorderStyle((0x00000038 & $borderLines) >> 3)); + $objStyle->getBorders()->getLeft()->setBorderStyle(self::_mapBorderStyle((0x00000038 & $borderLines) >> 3)); // bit: 8-6; mask: 0x000001C0; right line style - $objStyle->getBorders()->getRight()->setBorderStyle($this->_mapBorderStyle((0x000001C0 & $borderLines) >> 6)); + $objStyle->getBorders()->getRight()->setBorderStyle(self::_mapBorderStyle((0x000001C0 & $borderLines) >> 6)); // bit: 15-9; mask: 0x0000FE00; top line color index $objStyle->getBorders()->getTop()->colorIndex = (0x0000FE00 & $borderLines) >> 9; @@ -1600,7 +2039,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readXfExt() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1616,28 +2055,28 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 12; size: 2; record version // offset: 14; size: 2; index to XF record which this record modifies - $ixfe = $this->_GetInt2d($recordData, 14); + $ixfe = self::_GetInt2d($recordData, 14); // offset: 16; size: 2; not used // offset: 18; size: 2; number of extension properties that follow - $cexts = $this->_GetInt2d($recordData, 18); + $cexts = self::_GetInt2d($recordData, 18); // start reading the actual extension data $offset = 20; while ($offset < $length) { // extension type - $extType = $this->_GetInt2d($recordData, $offset); + $extType = self::_GetInt2d($recordData, $offset); // extension length - $cb = $this->_GetInt2d($recordData, $offset + 2); + $cb = self::_GetInt2d($recordData, $offset + 2); // extension data $extData = substr($recordData, $offset + 4, $cb); switch ($extType) { case 4: // fill start color - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1653,7 +2092,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 5: // fill end color - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1669,7 +2108,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 7: // border color top - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1685,7 +2124,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 8: // border color bottom - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1701,7 +2140,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 9: // border color left - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1717,7 +2156,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 10: // border color right - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1733,7 +2172,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 11: // border color diagonal - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1749,7 +2188,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 13: // font color - $xclfType = $this->_GetInt2d($extData, 0); // color type + $xclfType = self::_GetInt2d($extData, 0); // color type $xclrValue = substr($extData, 4, 4); // color value (value based on color type) if ($xclfType == 2) { @@ -1776,7 +2215,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readStyle() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1784,7 +2223,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; index to XF record and flag for built-in style - $ixfe = $this->_GetInt2d($recordData, 0); + $ixfe = self::_GetInt2d($recordData, 0); // bit: 11-0; mask 0x0FFF; index to XF record $xfIndex = (0x0FFF & $ixfe) >> 0; @@ -1816,7 +2255,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readPalette() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1824,12 +2263,12 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; number of following colors - $nm = $this->_GetInt2d($recordData, 0); + $nm = self::_GetInt2d($recordData, 0); // list of RGB colors for ($i = 0; $i < $nm; ++$i) { $rgb = substr($recordData, 2 + 4 * $i, 4); - $this->_palette[] = $this->_readRGB($rgb); + $this->_palette[] = self::_readRGB($rgb); } } } @@ -1848,14 +2287,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readSheet() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 4; absolute stream position of the BOF record of the sheet - $rec_offset = $this->_GetInt4d($recordData, 0); + $rec_offset = self::_GetInt4d($recordData, 0); // offset: 4; size: 1; sheet state switch (ord($recordData{4})) { @@ -1870,7 +2309,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 6; size: var; sheet name if ($this->_version == self::XLS_BIFF8) { - $string = $this->_readUnicodeStringShort(substr($recordData, 6)); + $string = self::_readUnicodeStringShort(substr($recordData, 6)); $rec_name = $string['value']; } elseif ($this->_version == self::XLS_BIFF7) { $string = $this->_readByteStringShort(substr($recordData, 6)); @@ -1890,7 +2329,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readExternalBook() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1903,17 +2342,17 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (strlen($recordData) > 4) { // external reference // offset: 0; size: 2; number of sheet names ($nm) - $nm = $this->_GetInt2d($recordData, 0); + $nm = self::_GetInt2d($recordData, 0); $offset += 2; // offset: 2; size: var; encoded URL without sheet name (Unicode string, 16-bit length) - $encodedUrlString = $this->_readUnicodeStringLong(substr($recordData, 2)); + $encodedUrlString = self::_readUnicodeStringLong(substr($recordData, 2)); $offset += $encodedUrlString['size']; // offset: var; size: var; list of $nm sheet names (Unicode strings, 16-bit length) $externalSheetNames = array(); for ($i = 0; $i < $nm; ++$i) { - $externalSheetNameString = $this->_readUnicodeStringLong(substr($recordData, $offset)); + $externalSheetNameString = self::_readUnicodeStringLong(substr($recordData, $offset)); $externalSheetNames[] = $externalSheetNameString['value']; $offset += $externalSheetNameString['size']; } @@ -1953,7 +2392,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readExternName() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1962,14 +2401,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // external sheet references provided for named cells if ($this->_version == self::XLS_BIFF8) { // offset: 0; size: 2; options - $options = $this->_GetInt2d($recordData, 0); + $options = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; // offset: 4; size: 2; not used // offset: 6; size: var - $nameString = $this->_readUnicodeStringShort(substr($recordData, 6)); + $nameString = self::_readUnicodeStringShort(substr($recordData, 6)); // offset: var; size: var; formula data $offset = 6 + $nameString['size']; @@ -1987,7 +2426,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readExternSheet() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -1996,15 +2435,15 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // external sheet references provided for named cells if ($this->_version == self::XLS_BIFF8) { // offset: 0; size: 2; number of following ref structures - $nm = $this->_GetInt2d($recordData, 0); + $nm = self::_GetInt2d($recordData, 0); for ($i = 0; $i < $nm; ++$i) { $this->_ref[] = array( // offset: 2 + 6 * $i; index to EXTERNALBOOK record - 'externalBookIndex' => $this->_GetInt2d($recordData, 2 + 6 * $i), + 'externalBookIndex' => self::_GetInt2d($recordData, 2 + 6 * $i), // offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record - 'firstSheetIndex' => $this->_GetInt2d($recordData, 4 + 6 * $i), + 'firstSheetIndex' => self::_GetInt2d($recordData, 4 + 6 * $i), // offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record - 'lastSheetIndex' => $this->_GetInt2d($recordData, 6 + 6 * $i), + 'lastSheetIndex' => self::_GetInt2d($recordData, 6 + 6 * $i), ); } } @@ -2023,7 +2462,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readDefinedName() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2033,7 +2472,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // retrieves named cells // offset: 0; size: 2; option flags - $opts = $this->_GetInt2d($recordData, 0); + $opts = self::_GetInt2d($recordData, 0); // bit: 5; mask: 0x0020; 0 = user-defined name, 1 = built-in-name $isBuiltInName = (0x0020 & $opts) >> 5; @@ -2045,13 +2484,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 4; size: 2; size of the formula data (it can happen that this is zero) // note: there can also be additional data, this is not included in $flen - $flen = $this->_GetInt2d($recordData, 4); + $flen = self::_GetInt2d($recordData, 4); // offset: 8; size: 2; 0=Global name, otherwise index to sheet (1-based) - $scope = $this->_GetInt2d($recordData, 8); + $scope = self::_GetInt2d($recordData, 8); // offset: 14; size: var; Name (Unicode string without length field) - $string = $this->_readUnicodeString(substr($recordData, 14), $nlen); + $string = self::_readUnicodeString(substr($recordData, 14), $nlen); // offset: var; size: $flen; formula data $offset = 14 + $string['size']; @@ -2077,7 +2516,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readMsoDrawingGroup() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); // get spliced record data $splicedRecordData = $this->_getSplicedRecordData(); @@ -2112,14 +2551,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $pos += 4; // offset: 4; size: 4; number of following strings ($nm) - $nm = $this->_GetInt4d($recordData, 4); + $nm = self::_GetInt4d($recordData, 4); $pos += 4; // loop through the Unicode strings (16-bit length) for ($i = 0; $i < $nm; ++$i) { // number of characters in the Unicode string - $numChars = $this->_GetInt2d($recordData, $pos); + $numChars = self::_GetInt2d($recordData, $pos); $pos += 2; // option flags @@ -2137,13 +2576,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ($hasRichText) { // number of Rich-Text formatting runs - $formattingRuns = $this->_GetInt2d($recordData, $pos); + $formattingRuns = self::_GetInt2d($recordData, $pos); $pos += 2; } if ($hasAsian) { // size of Asian phonetic setting - $extendedRunLength = $this->_GetInt4d($recordData, $pos); + $extendedRunLength = self::_GetInt4d($recordData, $pos); $pos += 4; } @@ -2240,7 +2679,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // convert to UTF-8 - $retstr = $this->_encodeUTF16($retstr, $isCompressed); + $retstr = self::_encodeUTF16($retstr, $isCompressed); // read additional Rich-Text information, if any $fmtRuns = array(); @@ -2248,10 +2687,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // list of formatting runs for ($j = 0; $j < $formattingRuns; ++$j) { // first formatted character; zero-based - $charPos = $this->_GetInt2d($recordData, $pos + $j * 4); + $charPos = self::_GetInt2d($recordData, $pos + $j * 4); // index to font record - $fontIndex = $this->_GetInt2d($recordData, $pos + 2 + $j * 4); + $fontIndex = self::_GetInt2d($recordData, $pos + 2 + $j * 4); $fmtRuns[] = array( 'charPos' => $charPos, @@ -2282,7 +2721,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readPrintGridlines() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2290,7 +2729,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) { // offset: 0; size: 2; 0 = do not print sheet grid lines; 1 = print sheet gridlines - $printGridlines = (bool) $this->_GetInt2d($recordData, 0); + $printGridlines = (bool) self::_GetInt2d($recordData, 0); $this->_phpSheet->setPrintGridlines($printGridlines); } } @@ -2300,7 +2739,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readDefaultRowHeight() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2308,7 +2747,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 0; size: 2; option flags // offset: 2; size: 2; default height for unused rows, (twips 1/20 point) - $height = $this->_GetInt2d($recordData, 2); + $height = self::_GetInt2d($recordData, 2); $this->_phpSheet->getDefaultRowDimension()->setRowHeight($height / 20); } @@ -2317,7 +2756,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readSheetPr() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2326,16 +2765,16 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 0; size: 2 // bit: 6; mask: 0x0040; 0 = outline buttons above outline group - $isSummaryBelow = (0x0040 & $this->_GetInt2d($recordData, 0)) >> 6; + $isSummaryBelow = (0x0040 & self::_GetInt2d($recordData, 0)) >> 6; $this->_phpSheet->setShowSummaryBelow($isSummaryBelow); // bit: 7; mask: 0x0080; 0 = outline buttons left of outline group - $isSummaryRight = (0x0080 & $this->_GetInt2d($recordData, 0)) >> 7; + $isSummaryRight = (0x0080 & self::_GetInt2d($recordData, 0)) >> 7; $this->_phpSheet->setShowSummaryRight($isSummaryRight); // bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages // this corresponds to radio button setting in page setup dialog in Excel - $this->_isFitToPages = (bool) ((0x0100 & $this->_GetInt2d($recordData, 0)) >> 8); + $this->_isFitToPages = (bool) ((0x0100 & self::_GetInt2d($recordData, 0)) >> 8); } /** @@ -2343,7 +2782,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readHorizontalPageBreaks() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2352,13 +2791,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) { // offset: 0; size: 2; number of the following row index structures - $nm = $this->_GetInt2d($recordData, 0); + $nm = self::_GetInt2d($recordData, 0); // offset: 2; size: 6 * $nm; list of $nm row index structures for ($i = 0; $i < $nm; ++$i) { - $r = $this->_GetInt2d($recordData, 2 + 6 * $i); - $cf = $this->_GetInt2d($recordData, 2 + 6 * $i + 2); - $cl = $this->_GetInt2d($recordData, 2 + 6 * $i + 4); + $r = self::_GetInt2d($recordData, 2 + 6 * $i); + $cf = self::_GetInt2d($recordData, 2 + 6 * $i + 2); + $cl = self::_GetInt2d($recordData, 2 + 6 * $i + 4); // not sure why two column indexes are necessary? $this->_phpSheet->setBreakByColumnAndRow($cf, $r, PHPExcel_Worksheet::BREAK_ROW); @@ -2371,7 +2810,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readVerticalPageBreaks() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2379,13 +2818,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) { // offset: 0; size: 2; number of the following column index structures - $nm = $this->_GetInt2d($recordData, 0); + $nm = self::_GetInt2d($recordData, 0); // offset: 2; size: 6 * $nm; list of $nm row index structures for ($i = 0; $i < $nm; ++$i) { - $c = $this->_GetInt2d($recordData, 2 + 6 * $i); - $rf = $this->_GetInt2d($recordData, 2 + 6 * $i + 2); - $rl = $this->_GetInt2d($recordData, 2 + 6 * $i + 4); + $c = self::_GetInt2d($recordData, 2 + 6 * $i); + $rf = self::_GetInt2d($recordData, 2 + 6 * $i + 2); + $rl = self::_GetInt2d($recordData, 2 + 6 * $i + 4); // not sure why two row indexes are necessary? $this->_phpSheet->setBreakByColumnAndRow($c, $rf, PHPExcel_Worksheet::BREAK_COLUMN); @@ -2398,7 +2837,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readHeader() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2409,7 +2848,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // realized that $recordData can be empty even when record exists if ($recordData) { if ($this->_version == self::XLS_BIFF8) { - $string = $this->_readUnicodeStringLong($recordData); + $string = self::_readUnicodeStringLong($recordData); } else { $string = $this->_readByteStringShort($recordData); } @@ -2425,7 +2864,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readFooter() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2436,7 +2875,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // realized that $recordData can be empty even when record exists if ($recordData) { if ($this->_version == self::XLS_BIFF8) { - $string = $this->_readUnicodeStringLong($recordData); + $string = self::_readUnicodeStringLong($recordData); } else { $string = $this->_readByteStringShort($recordData); } @@ -2451,7 +2890,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readHcenter() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2459,7 +2898,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; 0 = print sheet left aligned, 1 = print sheet centered horizontally - $isHorizontalCentered = (bool) $this->_GetInt2d($recordData, 0); + $isHorizontalCentered = (bool) self::_GetInt2d($recordData, 0); $this->_phpSheet->getPageSetup()->setHorizontalCentered($isHorizontalCentered); } @@ -2470,7 +2909,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readVcenter() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2478,7 +2917,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; 0 = print sheet aligned at top page border, 1 = print sheet vertically centered - $isVerticalCentered = (bool) $this->_GetInt2d($recordData, 0); + $isVerticalCentered = (bool) self::_GetInt2d($recordData, 0); $this->_phpSheet->getPageSetup()->setVerticalCentered($isVerticalCentered); } @@ -2489,7 +2928,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readLeftMargin() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2497,7 +2936,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 8 - $this->_phpSheet->getPageMargins()->setLeft($this->_extractNumber($recordData)); + $this->_phpSheet->getPageMargins()->setLeft(self::_extractNumber($recordData)); } } @@ -2506,7 +2945,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readRightMargin() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2514,7 +2953,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 8 - $this->_phpSheet->getPageMargins()->setRight($this->_extractNumber($recordData)); + $this->_phpSheet->getPageMargins()->setRight(self::_extractNumber($recordData)); } } @@ -2523,7 +2962,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readTopMargin() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2531,7 +2970,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 8 - $this->_phpSheet->getPageMargins()->setTop($this->_extractNumber($recordData)); + $this->_phpSheet->getPageMargins()->setTop(self::_extractNumber($recordData)); } } @@ -2540,7 +2979,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readBottomMargin() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2548,7 +2987,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 8 - $this->_phpSheet->getPageMargins()->setBottom($this->_extractNumber($recordData)); + $this->_phpSheet->getPageMargins()->setBottom(self::_extractNumber($recordData)); } } @@ -2557,7 +2996,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readPageSetup() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2565,25 +3004,25 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; paper size - $paperSize = $this->_GetInt2d($recordData, 0); + $paperSize = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; scaling factor - $scale = $this->_GetInt2d($recordData, 2); + $scale = self::_GetInt2d($recordData, 2); // offset: 6; size: 2; fit worksheet width to this number of pages, 0 = use as many as needed - $fitToWidth = $this->_GetInt2d($recordData, 6); + $fitToWidth = self::_GetInt2d($recordData, 6); // offset: 8; size: 2; fit worksheet height to this number of pages, 0 = use as many as needed - $fitToHeight = $this->_GetInt2d($recordData, 8); + $fitToHeight = self::_GetInt2d($recordData, 8); // offset: 10; size: 2; option flags // bit: 1; mask: 0x0002; 0=landscape, 1=portrait - $isPortrait = (0x0002 & $this->_GetInt2d($recordData, 10)) >> 1; + $isPortrait = (0x0002 & self::_GetInt2d($recordData, 10)) >> 1; // bit: 2; mask: 0x0004; 1= paper size, scaling factor, paper orient. not init // when this bit is set, do not use flags for those properties - $isNotInit = (0x0004 & $this->_GetInt2d($recordData, 10)) >> 2; + $isNotInit = (0x0004 & self::_GetInt2d($recordData, 10)) >> 2; if (!$isNotInit) { $this->_phpSheet->getPageSetup()->setPaperSize($paperSize); @@ -2599,11 +3038,11 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // offset: 16; size: 8; header margin (IEEE 754 floating-point value) - $marginHeader = $this->_extractNumber(substr($recordData, 16, 8)); + $marginHeader = self::_extractNumber(substr($recordData, 16, 8)); $this->_phpSheet->getPageMargins()->setHeader($marginHeader); // offset: 24; size: 8; footer margin (IEEE 754 floating-point value) - $marginFooter = $this->_extractNumber(substr($recordData, 24, 8)); + $marginFooter = self::_extractNumber(substr($recordData, 24, 8)); $this->_phpSheet->getPageMargins()->setFooter($marginFooter); } } @@ -2614,7 +3053,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readProtect() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2627,7 +3066,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 0; size: 2; // bit 0, mask 0x01; 1 = sheet is protected - $bool = (0x01 & $this->_GetInt2d($recordData, 0)) >> 0; + $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0; $this->_phpSheet->getProtection()->setSheet((bool)$bool); } @@ -2636,7 +3075,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readScenProtect() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2649,7 +3088,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 0; size: 2; // bit: 0, mask 0x01; 1 = scenarios are protected - $bool = (0x01 & $this->_GetInt2d($recordData, 0)) >> 0; + $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0; $this->_phpSheet->getProtection()->setScenarios((bool)$bool); } @@ -2659,7 +3098,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readObjectProtect() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2672,7 +3111,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 0; size: 2; // bit: 0, mask 0x01; 1 = objects are protected - $bool = (0x01 & $this->_GetInt2d($recordData, 0)) >> 0; + $bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0; $this->_phpSheet->getProtection()->setObjects((bool)$bool); } @@ -2682,7 +3121,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readPassword() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2690,7 +3129,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; 16-bit hash value of password - $password = strtoupper(dechex($this->_GetInt2d($recordData, 0))); // the hashed password + $password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password $this->_phpSheet->getProtection()->setPassword($password, true); } } @@ -2700,14 +3139,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readDefColWidth() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; default column width - $width = $this->_GetInt2d($recordData, 0); + $width = self::_GetInt2d($recordData, 0); if ($width != 8) { $this->_phpSheet->getDefaultColumnDimension()->setWidth($width); } @@ -2718,7 +3157,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readColInfo() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2726,27 +3165,27 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; index to first column in range - $fc = $this->_GetInt2d($recordData, 0); // first column index + $fc = self::_GetInt2d($recordData, 0); // first column index // offset: 2; size: 2; index to last column in range - $lc = $this->_GetInt2d($recordData, 2); // first column index + $lc = self::_GetInt2d($recordData, 2); // first column index // offset: 4; size: 2; width of the column in 1/256 of the width of the zero character - $width = $this->_GetInt2d($recordData, 4); + $width = self::_GetInt2d($recordData, 4); // offset: 6; size: 2; index to XF record for default column formatting - $xfIndex = $this->_GetInt2d($recordData, 6); + $xfIndex = self::_GetInt2d($recordData, 6); // offset: 8; size: 2; option flags // bit: 0; mask: 0x0001; 1= columns are hidden - $isHidden = (0x0001 & $this->_GetInt2d($recordData, 8)) >> 0; + $isHidden = (0x0001 & self::_GetInt2d($recordData, 8)) >> 0; // bit: 10-8; mask: 0x0700; outline level of the columns (0 = no outline) - $level = (0x0700 & $this->_GetInt2d($recordData, 8)) >> 8; + $level = (0x0700 & self::_GetInt2d($recordData, 8)) >> 8; // bit: 12; mask: 0x1000; 1 = collapsed - $isCollapsed = (0x1000 & $this->_GetInt2d($recordData, 8)) >> 12; + $isCollapsed = (0x1000 & self::_GetInt2d($recordData, 8)) >> 12; // offset: 10; size: 2; not used @@ -2776,7 +3215,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readRow() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -2784,7 +3223,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; index of this row - $r = $this->_GetInt2d($recordData, 0); + $r = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; index to column of the first cell which is described by a cell record @@ -2793,10 +3232,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 6; size: 2; // bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point - $height = (0x7FFF & $this->_GetInt2d($recordData, 6)) >> 0; + $height = (0x7FFF & self::_GetInt2d($recordData, 6)) >> 0; // bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height - $useDefaultHeight = (0x8000 & $this->_GetInt2d($recordData, 6)) >> 15; + $useDefaultHeight = (0x8000 & self::_GetInt2d($recordData, 6)) >> 15; if (!$useDefaultHeight) { $this->_phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20); @@ -2809,22 +3248,22 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 12; size: 4; option flags and default row formatting // bit: 2-0: mask: 0x00000007; outline level of the row - $level = (0x00000007 & $this->_GetInt4d($recordData, 12)) >> 0; + $level = (0x00000007 & self::_GetInt4d($recordData, 12)) >> 0; $this->_phpSheet->getRowDimension($r + 1)->setOutlineLevel($level); // bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed - $isCollapsed = (0x00000010 & $this->_GetInt4d($recordData, 12)) >> 4; + $isCollapsed = (0x00000010 & self::_GetInt4d($recordData, 12)) >> 4; $this->_phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed); // bit: 5; mask: 0x00000020; 1 = row is hidden - $isHidden = (0x00000020 & $this->_GetInt4d($recordData, 12)) >> 5; + $isHidden = (0x00000020 & self::_GetInt4d($recordData, 12)) >> 5; $this->_phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden); // bit: 7; mask: 0x00000080; 1 = row has explicit format - $hasExplicitFormat = (0x00000080 & $this->_GetInt4d($recordData, 12)) >> 7; + $hasExplicitFormat = (0x00000080 & self::_GetInt4d($recordData, 12)) >> 7; // bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record - $xfIndex = (0x0FFF0000 & $this->_GetInt4d($recordData, 12)) >> 16; + $xfIndex = (0x0FFF0000 & self::_GetInt4d($recordData, 12)) >> 16; if ($hasExplicitFormat) { $this->_phpSheet->getRowDimension($r + 1)->setXfIndex($this->_mapCellXfIndex[$xfIndex]); @@ -2845,27 +3284,27 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readRk() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; index to row - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; index to column - $column = $this->_GetInt2d($recordData, 2); + $column = self::_GetInt2d($recordData, 2); $columnString = PHPExcel_Cell::stringFromColumnIndex($column); // Read cell? if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { // offset: 4; size: 2; index to XF record - $xfIndex = $this->_GetInt2d($recordData, 4); + $xfIndex = self::_GetInt2d($recordData, 4); // offset: 6; size: 4; RK value - $rknum = $this->_GetInt4d($recordData, 6); - $numValue = $this->_GetIEEE754($rknum); + $rknum = self::_GetInt4d($recordData, 6); + $numValue = self::_GetIEEE754($rknum); $cell = $this->_phpSheet->getCell($columnString . ($row + 1)); if (!$this->_readDataOnly) { @@ -2889,33 +3328,34 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readLabelSst() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; index to row - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; index to column - $column = $this->_GetInt2d($recordData, 2); + $column = self::_GetInt2d($recordData, 2); $columnString = PHPExcel_Cell::stringFromColumnIndex($column); // Read cell? if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { // offset: 4; size: 2; index to XF record - $xfIndex = $this->_GetInt2d($recordData, 4); + $xfIndex = self::_GetInt2d($recordData, 4); // offset: 6; size: 4; index to SST record - $index = $this->_GetInt4d($recordData, 6); + $index = self::_GetInt4d($recordData, 6); // add cell if (($fmtRuns = $this->_sst[$index]['fmtRuns']) && !$this->_readDataOnly) { // then we should treat as rich text $richText = new PHPExcel_RichText(); $charPos = 0; - for ($i = 0; $i <= count($this->_sst[$index]['fmtRuns']); ++$i) { + $sstCount = count($this->_sst[$index]['fmtRuns']); + for ($i = 0; $i <= $sstCount; ++$i) { if (isset($fmtRuns[$i])) { $text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos); $charPos = $fmtRuns[$i]['charPos']; @@ -2965,20 +3405,20 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readMulRk() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; index to row - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; index to first column - $colFirst = $this->_GetInt2d($recordData, 2); + $colFirst = self::_GetInt2d($recordData, 2); // offset: var; size: 2; index to last column - $colLast = $this->_GetInt2d($recordData, $length - 2); + $colLast = self::_GetInt2d($recordData, $length - 2); $columns = $colLast - $colFirst + 1; // offset within record data @@ -2991,10 +3431,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { // offset: var; size: 2; index to XF record - $xfIndex = $this->_GetInt2d($recordData, $offset); + $xfIndex = self::_GetInt2d($recordData, $offset); // offset: var; size: 4; RK value - $numValue = $this->_GetIEEE754($this->_GetInt4d($recordData, $offset + 2)); + $numValue = self::_GetIEEE754(self::_GetInt4d($recordData, $offset + 2)); $cell = $this->_phpSheet->getCell($columnString . ($row + 1)); if (!$this->_readDataOnly) { // add style @@ -3019,25 +3459,25 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readNumber() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; index to row - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size 2; index to column - $column = $this->_GetInt2d($recordData, 2); + $column = self::_GetInt2d($recordData, 2); $columnString = PHPExcel_Cell::stringFromColumnIndex($column); // Read cell? if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { // offset 4; size: 2; index to XF record - $xfIndex = $this->_GetInt2d($recordData, 4); + $xfIndex = self::_GetInt2d($recordData, 4); - $numValue = $this->_extractNumber(substr($recordData, 6, 8)); + $numValue = self::_extractNumber(substr($recordData, 6, 8)); $cell = $this->_phpSheet->getCell($columnString . ($row + 1)); if (!$this->_readDataOnly) { @@ -3060,24 +3500,24 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readFormula() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; row index - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; col index - $column = $this->_GetInt2d($recordData, 2); + $column = self::_GetInt2d($recordData, 2); $columnString = PHPExcel_Cell::stringFromColumnIndex($column); // offset: 20: size: variable; formula structure $formulaStructure = substr($recordData, 20); // offset: 14: size: 2; option flags, recalculate always, recalculate on open etc. - $options = $this->_GetInt2d($recordData, 14); + $options = self::_GetInt2d($recordData, 14); // bit: 0; mask: 0x0001; 1 = recalculate always // bit: 1; mask: 0x0002; 1 = calculate on open @@ -3093,8 +3533,8 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ($isPartOfSharedFormula) { // part of shared formula which means there will be a formula with a tExp token and nothing else // get the base cell, grab tExp token - $baseRow = $this->_GetInt2d($formulaStructure, 3); - $baseCol = $this->_GetInt2d($formulaStructure, 5); + $baseRow = self::_GetInt2d($formulaStructure, 3); + $baseCol = self::_GetInt2d($formulaStructure, 5); $this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1); } @@ -3109,7 +3549,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 16: size: 4; not used // offset: 4; size: 2; XF index - $xfIndex = $this->_GetInt2d($recordData, 4); + $xfIndex = self::_GetInt2d($recordData, 4); // offset: 6; size: 8; result of the formula if ( (ord($recordData{6}) == 0) @@ -3120,7 +3560,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $dataType = PHPExcel_Cell_DataType::TYPE_STRING; // read possible SHAREDFMLA record - $code = $this->_GetInt2d($this->_data, $this->_pos); + $code = self::_GetInt2d($this->_data, $this->_pos); if ($code == self::XLS_Type_SHAREDFMLA) { $this->_readSharedFmla(); } @@ -3142,7 +3582,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // Error formula. Error code is in +2 $dataType = PHPExcel_Cell_DataType::TYPE_ERROR; - $value = $this->_mapErrorCode(ord($recordData{8})); + $value = self::_mapErrorCode(ord($recordData{8})); } elseif ((ord($recordData{6}) == 3) && (ord($recordData{12}) == 255) @@ -3156,7 +3596,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // forumla result is a number, first 14 bytes like _NUMBER record $dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC; - $value = $this->_extractNumber(substr($recordData, 6, 8)); + $value = self::_extractNumber(substr($recordData, 6, 8)); } @@ -3200,7 +3640,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readSharedFmla() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -3232,14 +3672,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readString() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; if ($this->_version == self::XLS_BIFF8) { - $string = $this->_readUnicodeStringLong($recordData); + $string = self::_readUnicodeStringLong($recordData); $value = $string['value']; } else { $string = $this->_readByteStringLong($recordData); @@ -3259,23 +3699,23 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readBoolErr() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; row index - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; column index - $column = $this->_GetInt2d($recordData, 2); + $column = self::_GetInt2d($recordData, 2); $columnString = PHPExcel_Cell::stringFromColumnIndex($column); // Read cell? if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { // offset: 4; size: 2; index to XF record - $xfIndex = $this->_GetInt2d($recordData, 4); + $xfIndex = self::_GetInt2d($recordData, 4); // offset: 6; size: 1; the boolean value or error value $boolErr = ord($recordData{6}); @@ -3293,7 +3733,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 1: // error type - $value = $this->_mapErrorCode($boolErr); + $value = self::_mapErrorCode($boolErr); // add cell value $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_ERROR); @@ -3317,17 +3757,17 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readMulBlank() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; index to row - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; index to first column - $fc = $this->_GetInt2d($recordData, 2); + $fc = self::_GetInt2d($recordData, 2); // offset: 4; size: 2 x nc; list of indexes to XF records // add style information @@ -3337,7 +3777,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // Read cell? if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { - $xfIndex = $this->_GetInt2d($recordData, 4 + 2 * $i); + $xfIndex = self::_GetInt2d($recordData, 4 + 2 * $i); $this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]); } } @@ -3358,28 +3798,28 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readLabel() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; index to row - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; index to column - $column = $this->_GetInt2d($recordData, 2); + $column = self::_GetInt2d($recordData, 2); $columnString = PHPExcel_Cell::stringFromColumnIndex($column); // Read cell? if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { // offset: 4; size: 2; XF index - $xfIndex = $this->_GetInt2d($recordData, 4); + $xfIndex = self::_GetInt2d($recordData, 4); // add cell value // todo: what if string is very long? continue record if ($this->_version == self::XLS_BIFF8) { - $string = $this->_readUnicodeStringLong(substr($recordData, 6)); + $string = self::_readUnicodeStringLong(substr($recordData, 6)); $value = $string['value']; } else { $string = $this->_readByteStringLong(substr($recordData, 6)); @@ -3400,23 +3840,23 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readBlank() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; row index - $row = $this->_GetInt2d($recordData, 0); + $row = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; col index - $col = $this->_GetInt2d($recordData, 2); + $col = self::_GetInt2d($recordData, 2); $columnString = PHPExcel_Cell::stringFromColumnIndex($col); // Read cell? if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) { // offset: 4; size: 2; XF index - $xfIndex = $this->_GetInt2d($recordData, 4); + $xfIndex = self::_GetInt2d($recordData, 4); // add style information if (!$this->_readDataOnly) { @@ -3431,7 +3871,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readMsoDrawing() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); // get spliced record data $splicedRecordData = $this->_getSplicedRecordData(); @@ -3445,7 +3885,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readObj() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -3456,16 +3896,32 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // recordData consists of an array of subrecords looking like this: - // ft: 2 bytes; id number - // cb: 2 bytes; size in bytes of following data + // ft: 2 bytes; ftCmo type (0x15) + // cb: 2 bytes; size in bytes of ftCmo data + // ot: 2 bytes; Object Type + // id: 2 bytes; Object id number + // grbit: 2 bytes; Option Flags // data: var; subrecord data // for now, we are just interested in the second subrecord containing the object type - $ot = $this->_GetInt2d($recordData, 4); + $ftCmoType = self::_GetInt2d($recordData, 0); + $cbCmoSize = self::_GetInt2d($recordData, 2); + $otObjType = self::_GetInt2d($recordData, 4); + $idObjID = self::_GetInt2d($recordData, 6); + $grbitOpts = self::_GetInt2d($recordData, 6); $this->_objs[] = array( - 'type' => $ot, + 'ftCmoType' => $ftCmoType, + 'cbCmoSize' => $cbCmoSize, + 'otObjType' => $otObjType, + 'idObjID' => $idObjID, + 'grbitOpts' => $grbitOpts ); + $this->textObjRef = $idObjID; + +// echo '_readObj()
'; +// var_dump(end($this->_objs)); +// echo '
'; } /** @@ -3473,14 +3929,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readWindow2() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; option flags - $options = $this->_GetInt2d($recordData, 0); + $options = self::_GetInt2d($recordData, 0); // bit: 1; mask: 0x0002; 0 = do not show gridlines, 1 = show gridlines $showGridlines = (bool) ((0x0002 & $options) >> 1); @@ -3508,17 +3964,17 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readScl() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record $this->_pos += 4 + $length; // offset: 0; size: 2; numerator of the view magnification - $numerator = $this->_GetInt2d($recordData, 0); + $numerator = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; numerator of the view magnification - $denumerator = $this->_GetInt2d($recordData, 2); + $denumerator = self::_GetInt2d($recordData, 2); // set the zoom scale (in percent) $this->_phpSheet->getSheetView()->setZoomScale($numerator * 100 / $denumerator); @@ -3529,7 +3985,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readPane() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -3537,10 +3993,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if (!$this->_readDataOnly) { // offset: 0; size: 2; position of vertical split - $px = $this->_GetInt2d($recordData, 0); + $px = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; position of horizontal split - $py = $this->_GetInt2d($recordData, 2); + $py = self::_GetInt2d($recordData, 2); if ($this->_frozen) { // frozen panes @@ -3556,7 +4012,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readSelection() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -3567,14 +4023,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $paneId = ord($recordData{0}); // offset: 1; size: 2; index to row of the active cell - $r = $this->_GetInt2d($recordData, 1); + $r = self::_GetInt2d($recordData, 1); // offset: 3; size: 2; index to column of the active cell - $c = $this->_GetInt2d($recordData, 3); + $c = self::_GetInt2d($recordData, 3); // offset: 5; size: 2; index into the following cell range list to the // entry that contains the active cell - $index = $this->_GetInt2d($recordData, 5); + $index = self::_GetInt2d($recordData, 5); // offset: 7; size: var; cell range address list containing all selected cell ranges $data = substr($recordData, 7); @@ -3601,6 +4057,25 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } } + private function _includeCellRangeFiltered($cellRangeAddress) + { + $includeCellRange = true; + if (!is_null($this->getReadFilter())) { + $includeCellRange = false; + $rangeBoundaries = PHPExcel_Cell::getRangeBoundaries($cellRangeAddress); + $rangeBoundaries[1][0]++; + for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; $row++) { + for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; $column++) { + if ($this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle())) { + $includeCellRange = true; + break 2; + } + } + } + } + return $includeCellRange; + } + /** * MERGEDCELLS * @@ -3612,7 +4087,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readMergedCells() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -3621,7 +4096,9 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) { $cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($recordData); foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) { - $this->_phpSheet->mergeCells($cellRangeAddress); + if ($this->_includeCellRangeFiltered($cellRangeAddress)) { + $this->_phpSheet->mergeCells($cellRangeAddress); + } } } } @@ -3631,7 +4108,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readHyperLink() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer forward to next record @@ -3652,35 +4129,35 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 28, size: 4; option flags // bit: 0; mask: 0x00000001; 0 = no link or extant, 1 = file link or URL - $isFileLinkOrUrl = (0x00000001 & $this->_GetInt2d($recordData, 28)) >> 0; + $isFileLinkOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 0; // bit: 1; mask: 0x00000002; 0 = relative path, 1 = absolute path or URL - $isAbsPathOrUrl = (0x00000001 & $this->_GetInt2d($recordData, 28)) >> 1; + $isAbsPathOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 1; // bit: 2 (and 4); mask: 0x00000014; 0 = no description - $hasDesc = (0x00000014 & $this->_GetInt2d($recordData, 28)) >> 2; + $hasDesc = (0x00000014 & self::_GetInt2d($recordData, 28)) >> 2; // bit: 3; mask: 0x00000008; 0 = no text, 1 = has text - $hasText = (0x00000008 & $this->_GetInt2d($recordData, 28)) >> 3; + $hasText = (0x00000008 & self::_GetInt2d($recordData, 28)) >> 3; // bit: 7; mask: 0x00000080; 0 = no target frame, 1 = has target frame - $hasFrame = (0x00000080 & $this->_GetInt2d($recordData, 28)) >> 7; + $hasFrame = (0x00000080 & self::_GetInt2d($recordData, 28)) >> 7; // bit: 8; mask: 0x00000100; 0 = file link or URL, 1 = UNC path (inc. server name) - $isUNC = (0x00000100 & $this->_GetInt2d($recordData, 28)) >> 8; + $isUNC = (0x00000100 & self::_GetInt2d($recordData, 28)) >> 8; // offset within record data $offset = 32; if ($hasDesc) { // offset: 32; size: var; character count of description text - $dl = $this->_GetInt4d($recordData, 32); + $dl = self::_GetInt4d($recordData, 32); // offset: 36; size: var; character array of description text, no Unicode string header, always 16-bit characters, zero terminated - $desc = $this->_encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false); + $desc = self::_encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false); $offset += 4 + 2 * $dl; } if ($hasFrame) { - $fl = $this->_GetInt4d($recordData, $offset); + $fl = self::_GetInt4d($recordData, $offset); $offset += 4 + 2 * $fl; } @@ -3705,10 +4182,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: var; size: 16; GUID of URL Moniker $offset += 16; // offset: var; size: 4; size (in bytes) of character array of the URL including trailing zero word - $us = $this->_GetInt4d($recordData, $offset); + $us = self::_GetInt4d($recordData, $offset); $offset += 4; // offset: var; size: $us; character array of the URL, no Unicode string header, always 16-bit characters, zero-terminated - $url = $this->_encodeUTF16(substr($recordData, $offset, $us - 2), false); + $url = self::_encodeUTF16(substr($recordData, $offset, $us - 2), false); $url .= $hasText ? '#' : ''; $offset += $us; break; @@ -3723,16 +4200,16 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $offset += 16; // offset: var; size: 2; directory up-level count. - $upLevelCount = $this->_GetInt2d($recordData, $offset); + $upLevelCount = self::_GetInt2d($recordData, $offset); $offset += 2; // offset: var; size: 4; character count of the shortened file path and name, including trailing zero word - $sl = $this->_GetInt4d($recordData, $offset); + $sl = self::_GetInt4d($recordData, $offset); $offset += 4; // offset: var; size: sl; character array of the shortened file path and name in 8.3-DOS-format (compressed Unicode string) $shortenedFilePath = substr($recordData, $offset, $sl); - $shortenedFilePath = $this->_encodeUTF16($shortenedFilePath, true); + $shortenedFilePath = self::_encodeUTF16($shortenedFilePath, true); $shortenedFilePath = substr($shortenedFilePath, 0, -1); // remove trailing zero $offset += $sl; @@ -3742,13 +4219,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // extended file path // offset: var; size: 4; size of the following file link field including string lenth mark - $sz = $this->_GetInt4d($recordData, $offset); + $sz = self::_GetInt4d($recordData, $offset); $offset += 4; // only present if $sz > 0 if ($sz > 0) { // offset: var; size: 4; size of the character array of the extended file path and name - $xl = $this->_GetInt4d($recordData, $offset); + $xl = self::_GetInt4d($recordData, $offset); $offset += 4; // offset: var; size 2; unknown @@ -3756,7 +4233,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: var; size $xl; character array of the extended file path and name. $extendedFilePath = substr($recordData, $offset, $xl); - $extendedFilePath = $this->_encodeUTF16($extendedFilePath, false); + $extendedFilePath = self::_encodeUTF16($extendedFilePath, false); $offset += $xl; } @@ -3787,10 +4264,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader if ($hasText) { // offset: var; size: 4; character count of text mark including trailing zero word - $tl = $this->_GetInt4d($recordData, $offset); + $tl = self::_GetInt4d($recordData, $offset); $offset += 4; // offset: var; size: var; character array of the text mark without the # sign, no Unicode header, always 16-bit characters, zero-terminated - $text = $this->_encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false); + $text = self::_encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false); $url .= $text; } @@ -3806,7 +4283,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readDataValidations() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer forward to next record @@ -3818,7 +4295,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readDataValidation() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer forward to next record @@ -3829,7 +4306,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // offset: 0; size: 4; Options - $options = $this->_GetInt4d($recordData, 0); + $options = self::_GetInt4d($recordData, 0); // bit: 0-3; mask: 0x0000000F; type $type = (0x0000000F & $options) >> 0; @@ -3883,31 +4360,31 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 4; size: var; title of the prompt box $offset = 4; - $string = $this->_readUnicodeStringLong(substr($recordData, $offset)); + $string = self::_readUnicodeStringLong(substr($recordData, $offset)); $promptTitle = $string['value'] !== chr(0) ? $string['value'] : ''; $offset += $string['size']; // offset: var; size: var; title of the error box - $string = $this->_readUnicodeStringLong(substr($recordData, $offset)); + $string = self::_readUnicodeStringLong(substr($recordData, $offset)); $errorTitle = $string['value'] !== chr(0) ? $string['value'] : ''; $offset += $string['size']; // offset: var; size: var; text of the prompt box - $string = $this->_readUnicodeStringLong(substr($recordData, $offset)); + $string = self::_readUnicodeStringLong(substr($recordData, $offset)); $prompt = $string['value'] !== chr(0) ? $string['value'] : ''; $offset += $string['size']; // offset: var; size: var; text of the error box - $string = $this->_readUnicodeStringLong(substr($recordData, $offset)); + $string = self::_readUnicodeStringLong(substr($recordData, $offset)); $error = $string['value'] !== chr(0) ? $string['value'] : ''; $offset += $string['size']; // offset: var; size: 2; size of the formula data for the first condition - $sz1 = $this->_GetInt2d($recordData, $offset); + $sz1 = self::_GetInt2d($recordData, $offset); $offset += 2; // offset: var; size: 2; not used @@ -3929,7 +4406,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $offset += $sz1; // offset: var; size: 2; size of the formula data for the first condition - $sz2 = $this->_GetInt2d($recordData, $offset); + $sz2 = self::_GetInt2d($recordData, $offset); $offset += 2; // offset: var; size: 2; not used @@ -3977,7 +4454,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readSheetLayout() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -3993,13 +4470,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 12; size: 4; size of record data // Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?) - $sz = $this->_GetInt4d($recordData, 12); + $sz = self::_GetInt4d($recordData, 12); switch ($sz) { case 0x14: // offset: 16; size: 2; color index for sheet tab - $colorIndex = $this->_GetInt2d($recordData, 16); - $color = $this->_readColor($colorIndex); + $colorIndex = self::_GetInt2d($recordData, 16); + $color = self::_readColor($colorIndex,$this->_palette,$this->_version); $this->_phpSheet->getTabColor()->setRGB($color['rgb']); break; @@ -4016,7 +4493,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readSheetProtection() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -4033,7 +4510,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 4; size: 8; Currently not used and set to 0 // offset: 12; size: 2; Shared feature type index (2=Enhanced Protetion, 4=SmartTag) - $isf = $this->_GetInt2d($recordData, 12); + $isf = self::_GetInt2d($recordData, 12); if ($isf != 2) { return; } @@ -4044,7 +4521,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // rgbHdrSData, assume "Enhanced Protection" // offset: 19; size: 2; option flags - $options = $this->_GetInt2d($recordData, 19); + $options = self::_GetInt2d($recordData, 19); // bit: 0; mask 0x0001; 1 = user may edit objects, 0 = users must not edit objects $bool = (0x0001 & $options) >> 0; @@ -4116,7 +4593,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readRangeProtection() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // move stream pointer to next record @@ -4129,7 +4606,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $offset += 12; // offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag - $isf = $this->_GetInt2d($recordData, 12); + $isf = self::_GetInt2d($recordData, 12); if ($isf != 2) { // we only read FEAT records of type 2 return; @@ -4139,7 +4616,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $offset += 5; // offset: 19; size: 2; count of ref ranges this feature is on - $cref = $this->_GetInt2d($recordData, 19); + $cref = self::_GetInt2d($recordData, 19); $offset += 2; $offset += 6; @@ -4161,7 +4638,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $offset += 4; // offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit) - $wPassword = $this->_GetInt4d($recordData, $offset); + $wPassword = self::_GetInt4d($recordData, $offset); $offset += 4; // Apply range protection to sheet @@ -4176,7 +4653,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readImData() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); // get spliced record data $splicedRecordData = $this->_getSplicedRecordData(); @@ -4185,13 +4662,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // UNDER CONSTRUCTION // offset: 0; size: 2; image format - $cf = $this->_GetInt2d($recordData, 0); + $cf = self::_GetInt2d($recordData, 0); // offset: 2; size: 2; environment from which the file was written - $env = $this->_GetInt2d($recordData, 2); + $env = self::_GetInt2d($recordData, 2); // offset: 4; size: 4; length of the image data - $lcb = $this->_GetInt4d($recordData, 4); + $lcb = self::_GetInt4d($recordData, 4); // offset: 8; size: var; image data $iData = substr($recordData, 8); @@ -4201,22 +4678,22 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // BITMAPCOREINFO // 1. BITMAPCOREHEADER // offset: 0; size: 4; bcSize, Specifies the number of bytes required by the structure - $bcSize = $this->_GetInt4d($iData, 0); + $bcSize = self::_GetInt4d($iData, 0); // var_dump($bcSize); // offset: 4; size: 2; bcWidth, specifies the width of the bitmap, in pixels - $bcWidth = $this->_GetInt2d($iData, 4); + $bcWidth = self::_GetInt2d($iData, 4); // var_dump($bcWidth); // offset: 6; size: 2; bcHeight, specifies the height of the bitmap, in pixels. - $bcHeight = $this->_GetInt2d($iData, 6); + $bcHeight = self::_GetInt2d($iData, 6); // var_dump($bcHeight); $ih = imagecreatetruecolor($bcWidth, $bcHeight); // offset: 8; size: 2; bcPlanes, specifies the number of planes for the target device. This value must be 1 // offset: 10; size: 2; bcBitCount specifies the number of bits-per-pixel. This value must be 1, 4, 8, or 24 - $bcBitCount = $this->_GetInt2d($iData, 10); + $bcBitCount = self::_GetInt2d($iData, 10); // var_dump($bcBitCount); $rgbString = substr($iData, 12); @@ -4258,7 +4735,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _readContinue() { - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $recordData = substr($this->_data, $this->_pos + 4, $length); // check if we are reading drawing data @@ -4286,7 +4763,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // 0xF00D MsofbtClientTextbox $validSplitPoints = array(0xF003, 0xF004, 0xF00D); // add identifiers if we find more - $splitPoint = $this->_GetInt2d($recordData, 2); + $splitPoint = self::_GetInt2d($recordData, 2); if (in_array($splitPoint, $validSplitPoints)) { // get spliced record data (and move pointer to next record) $splicedRecordData = $this->_getSplicedRecordData(); @@ -4321,15 +4798,15 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader ++$i; // offset: 0; size: 2; identifier - $identifier = $this->_GetInt2d($this->_data, $this->_pos); + $identifier = self::_GetInt2d($this->_data, $this->_pos); // offset: 2; size: 2; length - $length = $this->_GetInt2d($this->_data, $this->_pos + 2); + $length = self::_GetInt2d($this->_data, $this->_pos + 2); $data .= substr($this->_data, $this->_pos + 4, $length); $spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length; $this->_pos += 4 + $length; - $nextIdentifier = $this->_GetInt2d($this->_data, $this->_pos); + $nextIdentifier = self::_GetInt2d($this->_data, $this->_pos); } while ($nextIdentifier == self::XLS_Type_CONTINUE); @@ -4352,7 +4829,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader private function _getFormulaFromStructure($formulaStructure, $baseCell = 'A1') { // offset: 0; size: 2; size of the following formula data - $sz = $this->_GetInt2d($formulaStructure, 0); + $sz = self::_GetInt2d($formulaStructure, 0); // offset: 2; size: sz $formulaData = substr($formulaStructure, 2, $sz); @@ -4435,7 +4912,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader case 'tAdd': // addition case 'tConcat': // addition case 'tDiv': // division - case 'tEQ': // equaltiy + case 'tEQ': // equality case 'tGE': // greater than or equal case 'tGT': // greater than case 'tIsect': // intersection @@ -4527,7 +5004,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader unset($space2, $space3, $space4, $space5); break; case 'tArray': // array constant - $constantArray = $this->_readBIFF8ConstantArray($additionalData); + $constantArray = self::_readBIFF8ConstantArray($additionalData); $formulaStrings[] = $space1 . $space0 . $constantArray['value']; $additionalData = substr($additionalData, $constantArray['size']); // bite of chunk of additional data unset($space0, $space1); @@ -4615,9 +5092,9 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader case 0x17: // string $name = 'tStr'; // offset: 1; size: var; Unicode string, 8-bit string length - $string = $this->_readUnicodeStringShort(substr($formulaData, 1)); + $string = self::_readUnicodeStringShort(substr($formulaData, 1)); $size = 1 + $string['size']; - $data = $this->_UTF8toExcelDoubleQuoted($string['value']); + $data = self::_UTF8toExcelDoubleQuoted($string['value']); break; case 0x19: // Special attribute // offset: 1; size: 1; attribute type flags: @@ -4635,7 +5112,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader case 0x04: $name = 'tAttrChoose'; // offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1) - $nc = $this->_GetInt2d($formulaData, 2); + $nc = self::_GetInt2d($formulaData, 2); // offset: 4; size: 2 * $nc // offset: 4 + 2 * $nc; size: 2 $size = 2 * $nc + 6; @@ -4693,7 +5170,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 1; size: 1; error code $name = 'tErr'; $size = 2; - $data = $this->_mapErrorCode(ord($formulaData[1])); + $data = self::_mapErrorCode(ord($formulaData[1])); break; case 0x1D: // boolean // offset: 1; size: 1; 0 = false, 1 = true; @@ -4705,13 +5182,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 1; size: 2; unsigned 16-bit integer $name = 'tInt'; $size = 3; - $data = $this->_GetInt2d($formulaData, 1); + $data = self::_GetInt2d($formulaData, 1); break; case 0x1F: // number // offset: 1; size: 8; $name = 'tNum'; $size = 9; - $data = $this->_extractNumber(substr($formulaData, 1)); + $data = self::_extractNumber(substr($formulaData, 1)); $data = str_replace(',', '.', (string)$data); // in case non-English locale break; case 0x20: // array constant @@ -4728,7 +5205,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $name = 'tFunc'; $size = 3; // offset: 1; size: 2; index to built-in sheet function - switch ($this->_GetInt2d($formulaData, 1)) { + switch (self::_GetInt2d($formulaData, 1)) { case 2: $function = 'ISNA'; $args = 1; break; case 3: $function = 'ISERROR'; $args = 1; break; case 10: $function = 'NA'; $args = 0; break; @@ -4888,6 +5365,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader case 352: $function = 'DATESTRING'; $args = 1; break; case 353: $function = 'NUMBERSTRING'; $args = 2; break; case 360: $function = 'PHONETIC'; $args = 1; break; + case 368: $function = 'BAHTTEXT'; $args = 1; break; default: throw new Exception('Unrecognized function in formula'); break; @@ -4902,7 +5380,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 1; size: 1; number of arguments $args = ord($formulaData[1]); // offset: 2: size: 2; index to built-in sheet function - $index = $this->_GetInt2d($formulaData, 2); + $index = self::_GetInt2d($formulaData, 2); switch ($index) { case 0: $function = 'COUNT'; break; case 1: $function = 'IF'; break; @@ -5004,7 +5482,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $name = 'tName'; $size = 5; // offset: 1; size: 2; one-based index to definedname record - $definedNameIndex = $this->_GetInt2d($formulaData, 1) - 1; + $definedNameIndex = self::_GetInt2d($formulaData, 1) - 1; // offset: 2; size: 2; not used $data = $this->_definedname[$definedNameIndex]['name']; break; @@ -5028,7 +5506,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $name = 'tMemArea'; // offset: 1; size: 4; not used // offset: 5; size: 2; size of the following subexpression - $subSize = $this->_GetInt2d($formulaData, 5); + $subSize = self::_GetInt2d($formulaData, 5); $size = 7 + $subSize; $data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize)); break; @@ -5038,7 +5516,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $name = 'tMemErr'; // offset: 1; size: 4; not used // offset: 5; size: 2; size of the following subexpression - $subSize = $this->_GetInt2d($formulaData, 5); + $subSize = self::_GetInt2d($formulaData, 5); $size = 7 + $subSize; $data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize)); break; @@ -5047,7 +5525,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader case 0x69: $name = 'tMemFunc'; // offset: 1; size: 2; size of the following sub-expression - $subSize = $this->_GetInt2d($formulaData, 1); + $subSize = self::_GetInt2d($formulaData, 1); $size = 3 + $subSize; $data = $this->_getFormulaFromData(substr($formulaData, 3, $subSize)); break; @@ -5075,7 +5553,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $size = 7; // offset: 1; size: 2; index to REF entry in EXTERNSHEET record // offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record - $index = $this->_GetInt2d($formulaData, 3); + $index = self::_GetInt2d($formulaData, 3); // assume index is to EXTERNNAME record $data = $this->_externalNames[$index - 1]['name']; // offset: 5; size: 2; not used @@ -5089,7 +5567,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader try { // offset: 1; size: 2; index to REF entry - $sheetRange = $this->_readSheetRangeByRefIndex($this->_GetInt2d($formulaData, 1)); + $sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1)); // offset: 3; size: 4; cell address $cellAddress = $this->_readBIFF8CellAddress(substr($formulaData, 3, 4)); @@ -5108,7 +5586,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader try { // offset: 1; size: 2; index to REF entry - $sheetRange = $this->_readSheetRangeByRefIndex($this->_GetInt2d($formulaData, 1)); + $sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1)); // offset: 3; size: 8; cell address $cellRangeAddress = $this->_readBIFF8CellRangeAddress(substr($formulaData, 3, 8)); @@ -5143,19 +5621,19 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader private function _readBIFF8CellAddress($cellAddressStructure) { // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767)) - $row = $this->_GetInt2d($cellAddressStructure, 0) + 1; + $row = self::_GetInt2d($cellAddressStructure, 0) + 1; // offset: 2; size: 2; index to column or column offset + relative flags // bit: 7-0; mask 0x00FF; column index - $column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & $this->_GetInt2d($cellAddressStructure, 2)); + $column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($cellAddressStructure, 2)); // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index) - if (!(0x4000 & $this->_GetInt2d($cellAddressStructure, 2))) { + if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) { $column = '$' . $column; } // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index) - if (!(0x8000 & $this->_GetInt2d($cellAddressStructure, 2))) { + if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) { $row = '$' . $row; } @@ -5177,16 +5655,16 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1; // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767)) - $rowIndex = $this->_GetInt2d($cellAddressStructure, 0); - $row = $this->_GetInt2d($cellAddressStructure, 0) + 1; + $rowIndex = self::_GetInt2d($cellAddressStructure, 0); + $row = self::_GetInt2d($cellAddressStructure, 0) + 1; // offset: 2; size: 2; index to column or column offset + relative flags // bit: 7-0; mask 0x00FF; column index - $colIndex = 0x00FF & $this->_GetInt2d($cellAddressStructure, 2); + $colIndex = 0x00FF & self::_GetInt2d($cellAddressStructure, 2); // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index) - if (!(0x4000 & $this->_GetInt2d($cellAddressStructure, 2))) { + if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) { $column = PHPExcel_Cell::stringFromColumnIndex($colIndex); $column = '$' . $column; } else { @@ -5195,7 +5673,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index) - if (!(0x8000 & $this->_GetInt2d($cellAddressStructure, 2))) { + if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) { $row = '$' . $row; } else { $rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536; @@ -5217,10 +5695,10 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader private function _readBIFF5CellRangeAddressFixed($subData) { // offset: 0; size: 2; index to first row - $fr = $this->_GetInt2d($subData, 0) + 1; + $fr = self::_GetInt2d($subData, 0) + 1; // offset: 2; size: 2; index to last row - $lr = $this->_GetInt2d($subData, 2) + 1; + $lr = self::_GetInt2d($subData, 2) + 1; // offset: 4; size: 1; index to first column $fc = ord($subData{4}); @@ -5255,16 +5733,16 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader private function _readBIFF8CellRangeAddressFixed($subData) { // offset: 0; size: 2; index to first row - $fr = $this->_GetInt2d($subData, 0) + 1; + $fr = self::_GetInt2d($subData, 0) + 1; // offset: 2; size: 2; index to last row - $lr = $this->_GetInt2d($subData, 2) + 1; + $lr = self::_GetInt2d($subData, 2) + 1; // offset: 4; size: 2; index to first column - $fc = $this->_GetInt2d($subData, 4); + $fc = self::_GetInt2d($subData, 4); // offset: 6; size: 2; index to last column - $lc = $this->_GetInt2d($subData, 6); + $lc = self::_GetInt2d($subData, 6); // check values if ($fr > $lr || $fc > $lc) { @@ -5295,38 +5773,38 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // not just return e.g. 'A1' and not 'A1:A1' ? // offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767)) - $fr = $this->_GetInt2d($subData, 0) + 1; + $fr = self::_GetInt2d($subData, 0) + 1; // offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767)) - $lr = $this->_GetInt2d($subData, 2) + 1; + $lr = self::_GetInt2d($subData, 2) + 1; // offset: 4; size: 2; index to first column or column offset + relative flags // bit: 7-0; mask 0x00FF; column index - $fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & $this->_GetInt2d($subData, 4)); + $fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 4)); // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index) - if (!(0x4000 & $this->_GetInt2d($subData, 4))) { + if (!(0x4000 & self::_GetInt2d($subData, 4))) { $fc = '$' . $fc; } // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index) - if (!(0x8000 & $this->_GetInt2d($subData, 4))) { + if (!(0x8000 & self::_GetInt2d($subData, 4))) { $fr = '$' . $fr; } // offset: 6; size: 2; index to last column or column offset + relative flags // bit: 7-0; mask 0x00FF; column index - $lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & $this->_GetInt2d($subData, 6)); + $lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 6)); // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index) - if (!(0x4000 & $this->_GetInt2d($subData, 6))) { + if (!(0x4000 & self::_GetInt2d($subData, 6))) { $lc = '$' . $lc; } // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index) - if (!(0x8000 & $this->_GetInt2d($subData, 6))) { + if (!(0x8000 & self::_GetInt2d($subData, 6))) { $lr = '$' . $lr; } @@ -5351,18 +5829,18 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // not just return e.g. 'A1' and not 'A1:A1' ? // offset: 0; size: 2; first row - $frIndex = $this->_GetInt2d($subData, 0); // adjust below + $frIndex = self::_GetInt2d($subData, 0); // adjust below // offset: 2; size: 2; relative index to first row (0... 65535) should be treated as offset (-32768... 32767) - $lrIndex = $this->_GetInt2d($subData, 2); // adjust below + $lrIndex = self::_GetInt2d($subData, 2); // adjust below // offset: 4; size: 2; first column with relative/absolute flags // bit: 7-0; mask 0x00FF; column index - $fcIndex = 0x00FF & $this->_GetInt2d($subData, 4); + $fcIndex = 0x00FF & self::_GetInt2d($subData, 4); // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index) - if (!(0x4000 & $this->_GetInt2d($subData, 4))) { + if (!(0x4000 & self::_GetInt2d($subData, 4))) { // absolute column index $fc = PHPExcel_Cell::stringFromColumnIndex($fcIndex); $fc = '$' . $fc; @@ -5373,7 +5851,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index) - if (!(0x8000 & $this->_GetInt2d($subData, 4))) { + if (!(0x8000 & self::_GetInt2d($subData, 4))) { // absolute row index $fr = $frIndex + 1; $fr = '$' . $fr; @@ -5386,12 +5864,12 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 6; size: 2; last column with relative/absolute flags // bit: 7-0; mask 0x00FF; column index - $lcIndex = 0x00FF & $this->_GetInt2d($subData, 6); + $lcIndex = 0x00FF & self::_GetInt2d($subData, 6); $lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256; $lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex); // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index) - if (!(0x4000 & $this->_GetInt2d($subData, 6))) { + if (!(0x4000 & self::_GetInt2d($subData, 6))) { // absolute column index $lc = PHPExcel_Cell::stringFromColumnIndex($lcIndex); $lc = '$' . $lc; @@ -5402,7 +5880,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index) - if (!(0x8000 & $this->_GetInt2d($subData, 6))) { + if (!(0x8000 & self::_GetInt2d($subData, 6))) { // absolute row index $lr = $lrIndex + 1; $lr = '$' . $lr; @@ -5427,7 +5905,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $cellRangeAddresses = array(); // offset: 0; size: 2; number of the following cell range addresses - $nm = $this->_GetInt2d($subData, 0); + $nm = self::_GetInt2d($subData, 0); $offset = 2; // offset: 2; size: 8 * $nm; list of $nm (fixed) cell range addresses @@ -5454,7 +5932,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $cellRangeAddresses = array(); // offset: 0; size: 2; number of the following cell range addresses - $nm = $this->_GetInt2d($subData, 0); + $nm = self::_GetInt2d($subData, 0); $offset = 2; // offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses @@ -5534,13 +6012,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $arrayData * @return array */ - private function _readBIFF8ConstantArray($arrayData) + private static function _readBIFF8ConstantArray($arrayData) { // offset: 0; size: 1; number of columns decreased by 1 $nc = ord($arrayData[0]); // offset: 1; size: 2; number of rows decreased by 1 - $nr = $this->_GetInt2d($arrayData, 1); + $nr = self::_GetInt2d($arrayData, 1); $size = 3; // initialize $arrayData = substr($arrayData, 3); @@ -5549,7 +6027,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader for ($r = 1; $r <= $nr + 1; ++$r) { $items = array(); for ($c = 1; $c <= $nc + 1; ++$c) { - $constant = $this->_readBIFF8Constant($arrayData); + $constant = self::_readBIFF8Constant($arrayData); $items[] = $constant['value']; $arrayData = substr($arrayData, $constant['size']); $size += $constant['size']; @@ -5572,7 +6050,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $valueData * @return array */ - private function _readBIFF8Constant($valueData) + private static function _readBIFF8Constant($valueData) { // offset: 0; size: 1; identifier for type of constant $identifier = ord($valueData[0]); @@ -5584,12 +6062,12 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 0x01: // number // offset: 1; size: 8; IEEE 754 floating-point value - $value = $this->_extractNumber(substr($valueData, 1, 8)); + $value = self::_extractNumber(substr($valueData, 1, 8)); $size = 9; break; case 0x02: // string value // offset: 1; size: var; Unicode string, 16-bit string length - $string = $this->_readUnicodeStringLong(substr($valueData, 1)); + $string = self::_readUnicodeStringLong(substr($valueData, 1)); $value = '"' . $string['value'] . '"'; $size = 1 + $string['size']; break; @@ -5604,7 +6082,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader break; case 0x10: // error code // offset: 1; size: 1; error code - $value = $this->_mapErrorCode(ord($valueData[1])); + $value = self::_mapErrorCode(ord($valueData[1])); $size = 9; break; } @@ -5621,7 +6099,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $rgb Encoded RGB value (4 bytes) * @return array */ - private function _readRGB($rgb) + private static function _readRGB($rgb) { // offset: 0; size 1; Red component $r = ord($rgb{0}); @@ -5633,7 +6111,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader $b = ord($rgb{2}); // HEX notation, e.g. 'FF00FC' - $rgb = sprintf('%02X', $r) . sprintf('%02X', $g) . sprintf('%02X', $b); + $rgb = sprintf('%02X%02X%02X', $r, $g, $b); return array('rgb' => $rgb); } @@ -5669,7 +6147,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader private function _readByteStringLong($subData) { // offset: 0; size: 2; length of the string (character count) - $ln = $this->_GetInt2d($subData, 0); + $ln = self::_GetInt2d($subData, 0); // offset: 2: size: var; character array (8-bit characters) $value = $this->_decodeCodepage(substr($subData, 2)); @@ -5689,14 +6167,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $subData * @return array */ - private function _readUnicodeStringShort($subData) + private static function _readUnicodeStringShort($subData) { $value = ''; // offset: 0: size: 1; length of the string (character count) $characterCount = ord($subData[0]); - $string = $this->_readUnicodeString(substr($subData, 1), $characterCount); + $string = self::_readUnicodeString(substr($subData, 1), $characterCount); // add 1 for the string length $string['size'] += 1; @@ -5712,14 +6190,14 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $subData * @return array */ - private function _readUnicodeStringLong($subData) + private static function _readUnicodeStringLong($subData) { $value = ''; // offset: 0: size: 2; length of the string (character count) - $characterCount = $this->_GetInt2d($subData, 0); + $characterCount = self::_GetInt2d($subData, 0); - $string = $this->_readUnicodeString(substr($subData, 2), $characterCount); + $string = self::_readUnicodeString(substr($subData, 2), $characterCount); // add 2 for the string length $string['size'] += 2; @@ -5736,7 +6214,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $characterCount * @return array */ - private function _readUnicodeString($subData, $characterCount) + private static function _readUnicodeString($subData, $characterCount) { $value = ''; @@ -5754,7 +6232,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader // offset: 1: size: var; character array // this offset assumes richtext and Asian phonetic settings are off which is generally wrong // needs to be fixed - $value = $this->_encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed); + $value = self::_encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed); return array( 'value' => $value, @@ -5769,7 +6247,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $value UTF-8 encoded string * @return string */ - private function _UTF8toExcelDoubleQuoted($value) + private static function _UTF8toExcelDoubleQuoted($value) { return '"' . str_replace('"', '""', $value) . '"'; } @@ -5780,22 +6258,22 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $data Binary string that is at least 8 bytes long * @return float */ - private function _extractNumber($data) + private static function _extractNumber($data) { - $rknumhigh = $this->_GetInt4d($data, 4); - $rknumlow = $this->_GetInt4d($data, 0); + $rknumhigh = self::_GetInt4d($data, 4); + $rknumlow = self::_GetInt4d($data, 0); $sign = ($rknumhigh & 0x80000000) >> 31; - $exp = ($rknumhigh & 0x7ff00000) >> 20; + $exp = (($rknumhigh & 0x7ff00000) >> 20) - 1023; $mantissa = (0x100000 | ($rknumhigh & 0x000fffff)); $mantissalow1 = ($rknumlow & 0x80000000) >> 31; $mantissalow2 = ($rknumlow & 0x7fffffff); - $value = $mantissa / pow( 2 , (20 - ($exp - 1023))); + $value = $mantissa / pow( 2 , (20 - $exp)); if ($mantissalow1 != 0) { - $value += 1 / pow (2 , (21 - ($exp - 1023))); + $value += 1 / pow (2 , (21 - $exp)); } - $value += $mantissalow2 / pow (2 , (52 - ($exp - 1023))); + $value += $mantissalow2 / pow (2 , (52 - $exp)); if ($sign) { $value = -1 * $value; } @@ -5803,7 +6281,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader return $value; } - private function _GetIEEE754($rknum) + private static function _GetIEEE754($rknum) { if (($rknum & 0x02) != 0) { $value = $rknum >> 2; @@ -5836,15 +6314,13 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param bool $compressed * @return string */ - private function _encodeUTF16($string, $compressed = '') + private static function _encodeUTF16($string, $compressed = '') { if ($compressed) { - $string = $this->_uncompressByteString($string); + $string = self::_uncompressByteString($string); } - $result = PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE'); - - return $result; + return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE'); } /** @@ -5853,10 +6329,11 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param string $string * @return string */ - private function _uncompressByteString($string) + private static function _uncompressByteString($string) { $uncompressedString = ''; - for ($i = 0; $i < strlen($string); ++$i) { + $strLen = strlen($string); + for ($i = 0; $i < $strLen; ++$i) { $uncompressedString .= $string[$i] . "\0"; } @@ -5871,8 +6348,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader */ private function _decodeCodepage($string) { - $result = PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->_codepage); - return $result; + return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->_codepage); } /** @@ -5882,7 +6358,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $pos * @return int */ - private function _GetInt2d($data, $pos) + public static function _GetInt2d($data, $pos) { return ord($data[$pos]) | (ord($data[$pos + 1]) << 8); } @@ -5894,13 +6370,11 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $pos * @return int */ - private function _GetInt4d($data, $pos) + public static function _GetInt4d($data, $pos) { - //return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | - // (ord($data[$pos + 2]) << 16) | (ord($data[$pos + 3]) << 24); - // FIX: represent numbers correctly on 64-bit system // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334 + // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems $_or_24 = ord($data[$pos + 3]); if ($_or_24 >= 128) { // negative number @@ -5915,23 +6389,24 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * Read color * * @param int $color Indexed color + * @param array $palette Color palette * @return array RGB color value, example: array('rgb' => 'FF0000') */ - private function _readColor($color) + private static function _readColor($color,$palette,$version) { if ($color <= 0x07 || $color >= 0x40) { // special built-in color - $color = $this->_mapBuiltInColor($color); - } else if (isset($this->_palette) && isset($this->_palette[$color - 8])) { + return self::_mapBuiltInColor($color); + } elseif (isset($palette) && isset($palette[$color - 8])) { // palette color, color index 0x08 maps to pallete index 0 - $color = $this->_palette[$color - 8]; + return $palette[$color - 8]; } else { // default color table - if ($this->_version == self::XLS_BIFF8) { - $color = $this->_mapColor($color); + if ($version == self::XLS_BIFF8) { + return self::_mapColor($color); } else { // BIFF5 - $color = $this->_mapColorBIFF5($color); + return self::_mapColorBIFF5($color); } } @@ -5946,7 +6421,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $index * @return string */ - private function _mapBorderStyle($index) + private static function _mapBorderStyle($index) { switch ($index) { case 0x00: return PHPExcel_Style_Border::BORDER_NONE; @@ -5974,7 +6449,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $index * @return string */ - private function _mapFillPattern($index) + private static function _mapFillPattern($index) { switch ($index) { case 0x00: return PHPExcel_Style_Fill::FILL_NONE; @@ -6006,7 +6481,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $subData * @return string */ - private function _mapErrorCode($subData) + private static function _mapErrorCode($subData) { switch ($subData) { case 0x00: return '#NULL!'; break; @@ -6026,7 +6501,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $color Indexed color * @return array */ - private function _mapBuiltInColor($color) + private static function _mapBuiltInColor($color) { switch ($color) { case 0x00: return array('rgb' => '000000'); @@ -6049,7 +6524,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $subData * @return array */ - private function _mapColorBIFF5($subData) + private static function _mapColorBIFF5($subData) { switch ($subData) { case 0x08: return array('rgb' => '000000'); @@ -6118,7 +6593,7 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader * @param int $subData * @return array */ - private function _mapColor($subData) + private static function _mapColor($subData) { switch ($subData) { case 0x08: return array('rgb' => '000000'); @@ -6181,4 +6656,12 @@ class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader } } + private function _parseRichText($is = '') { + $value = new PHPExcel_RichText(); + + $value->createText($is); + + return $value; + } + } diff --git a/libraries/PHPExcel/PHPExcel/Reader/Excel5/Escher.php b/libraries/PHPExcel/PHPExcel/Reader/Excel5/Escher.php index b7c67e91f..e1a25bb47 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/Excel5/Escher.php +++ b/libraries/PHPExcel/PHPExcel/Reader/Excel5/Escher.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Reader_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_Excel5_Escher { @@ -108,9 +108,8 @@ class PHPExcel_Reader_Excel5_Escher // Parse Escher stream while ($this->_pos < $this->_dataSize) { - // offset: 2; size: 2: Record Type - $fbt = $this->_GetInt2d($this->_data, $this->_pos + 2); + $fbt = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos + 2); switch ($fbt) { case self::DGGCONTAINER: $this->_readDggContainer(); break; @@ -144,15 +143,15 @@ class PHPExcel_Reader_Excel5_Escher private function _readDefault() { // offset 0; size: 2; recVer and recInstance - $verInstance = $this->_GetInt2d($this->_data, $this->_pos); + $verInstance = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos); // offset: 2; size: 2: Record Type - $fbt = $this->_GetInt2d($this->_data, $this->_pos + 2); + $fbt = PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos + 2); // bit: 0-3; mask: 0x000F; recVer $recVer = (0x000F & $verInstance) >> 0; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -164,7 +163,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readDggContainer() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -182,7 +181,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readDgg() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -194,7 +193,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readBstoreContainer() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -215,9 +214,9 @@ class PHPExcel_Reader_Excel5_Escher // offset: 0; size: 2; recVer and recInstance // bit: 4-15; mask: 0xFFF0; recInstance - $recInstance = (0xFFF0 & $this->_GetInt2d($this->_data, $this->_pos)) >> 4; + $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -239,16 +238,16 @@ class PHPExcel_Reader_Excel5_Escher $rgbUid = substr($recordData, 2, 16); // offset: 18; size: 2; tag - $tag = $this->_GetInt2d($recordData, 18); + $tag = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 18); // offset: 20; size: 4; size of BLIP in bytes - $size = $this->_GetInt4d($recordData, 20); + $size = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 20); // offset: 24; size: 4; number of references to this BLIP - $cRef = $this->_GetInt4d($recordData, 24); + $cRef = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 24); // offset: 28; size: 4; MSOFO file offset - $foDelay = $this->_GetInt4d($recordData, 28); + $foDelay = PHPExcel_Reader_Excel5::_GetInt4d($recordData, 28); // offset: 32; size: 1; unused1 $unused1 = ord($recordData{32}); @@ -281,9 +280,9 @@ class PHPExcel_Reader_Excel5_Escher // offset: 0; size: 2; recVer and recInstance // bit: 4-15; mask: 0xFFF0; recInstance - $recInstance = (0xFFF0 & $this->_GetInt2d($this->_data, $this->_pos)) >> 4; + $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -322,9 +321,9 @@ class PHPExcel_Reader_Excel5_Escher // offset: 0; size: 2; recVer and recInstance // bit: 4-15; mask: 0xFFF0; recInstance - $recInstance = (0xFFF0 & $this->_GetInt2d($this->_data, $this->_pos)) >> 4; + $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -363,9 +362,9 @@ class PHPExcel_Reader_Excel5_Escher // offset: 0; size: 2; recVer and recInstance // bit: 4-15; mask: 0xFFF0; recInstance - $recInstance = (0xFFF0 & $this->_GetInt2d($this->_data, $this->_pos)) >> 4; + $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -382,9 +381,9 @@ class PHPExcel_Reader_Excel5_Escher // offset: 0; size: 2; recVer and recInstance // bit: 4-15; mask: 0xFFF0; recInstance - $recInstance = (0xFFF0 & $this->_GetInt2d($this->_data, $this->_pos)) >> 4; + $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -396,7 +395,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readSplitMenuColors() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -408,7 +407,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readDgContainer() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -426,7 +425,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readDg() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -440,7 +439,7 @@ class PHPExcel_Reader_Excel5_Escher { // context is either context DgContainer or SpgrContainer - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -466,7 +465,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readSpContainer() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // add spContainer to spgrContainer @@ -486,7 +485,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readSpgr() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -501,9 +500,9 @@ class PHPExcel_Reader_Excel5_Escher // offset: 0; size: 2; recVer and recInstance // bit: 4-15; mask: 0xFFF0; recInstance - $recInstance = (0xFFF0 & $this->_GetInt2d($this->_data, $this->_pos)) >> 4; + $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -518,9 +517,9 @@ class PHPExcel_Reader_Excel5_Escher // offset: 0; size: 2; recVer and recInstance // bit: 4-15; mask: 0xFFF0; recInstance - $recInstance = (0xFFF0 & $this->_GetInt2d($this->_data, $this->_pos)) >> 4; + $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::_GetInt2d($this->_data, $this->_pos)) >> 4; - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -532,35 +531,35 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readClientAnchor() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record $this->_pos += 8 + $length; // offset: 2; size: 2; upper-left corner column index (0-based) - $c1 = $this->_GetInt2d($recordData, 2); + $c1 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 2); // offset: 4; size: 2; upper-left corner horizontal offset in 1/1024 of column width - $startOffsetX = $this->_GetInt2d($recordData, 4); + $startOffsetX = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 4); // offset: 6; size: 2; upper-left corner row index (0-based) - $r1 = $this->_GetInt2d($recordData, 6); + $r1 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 6); // offset: 8; size: 2; upper-left corner vertical offset in 1/256 of row height - $startOffsetY = $this->_GetInt2d($recordData, 8); + $startOffsetY = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 8); // offset: 10; size: 2; bottom-right corner column index (0-based) - $c2 = $this->_GetInt2d($recordData, 10); + $c2 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 10); // offset: 12; size: 2; bottom-right corner horizontal offset in 1/1024 of column width - $endOffsetX = $this->_GetInt2d($recordData, 12); + $endOffsetX = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 12); // offset: 14; size: 2; bottom-right corner row index (0-based) - $r2 = $this->_GetInt2d($recordData, 14); + $r2 = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 14); // offset: 16; size: 2; bottom-right corner vertical offset in 1/256 of row height - $endOffsetY = $this->_GetInt2d($recordData, 16); + $endOffsetY = PHPExcel_Reader_Excel5::_GetInt2d($recordData, 16); // set the start coordinates $this->_object->setStartCoordinates(PHPExcel_Cell::stringFromColumnIndex($c1) . ($r1 + 1)); @@ -586,7 +585,7 @@ class PHPExcel_Reader_Excel5_Escher */ private function _readClientData() { - $length = $this->_GetInt4d($this->_data, $this->_pos + 4); + $length = PHPExcel_Reader_Excel5::_GetInt4d($this->_data, $this->_pos + 4); $recordData = substr($this->_data, $this->_pos + 8, $length); // move stream pointer to next record @@ -609,7 +608,7 @@ class PHPExcel_Reader_Excel5_Escher $fopte = substr($data, 6 * $i, 6); // offset: 0; size: 2; opid - $opid = $this->_GetInt2d($fopte, 0); + $opid = PHPExcel_Reader_Excel5::_GetInt2d($fopte, 0); // bit: 0-13; mask: 0x3FFF; opid.opid $opidOpid = (0x3FFF & $opid) >> 0; @@ -621,7 +620,7 @@ class PHPExcel_Reader_Excel5_Escher $opidFComplex = (0x8000 & $opid) >> 15; // offset: 2; size: 4; the value for this property - $op = $this->_GetInt4d($fopte, 2); + $op = PHPExcel_Reader_Excel5::_GetInt4d($fopte, 2); if ($opidFComplex) { $complexData = substr($splicedComplexData, 0, $op); @@ -638,40 +637,4 @@ class PHPExcel_Reader_Excel5_Escher } } - /** - * Read 16-bit unsigned integer - * - * @param string $data - * @param int $pos - * @return int - */ - private function _GetInt2d($data, $pos) - { - return ord($data[$pos]) | (ord($data[$pos + 1]) << 8); - } - - /** - * Read 32-bit signed integer - * - * @param string $data - * @param int $pos - * @return int - */ - private function _GetInt4d($data, $pos) - { - //return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | - // (ord($data[$pos + 2]) << 16) | (ord($data[$pos + 3]) << 24); - - // FIX: represent numbers correctly on 64-bit system - // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334 - $_or_24 = ord($data[$pos + 3]); - if ($_or_24 >= 128) { - // negative number - $_ord_24 = -abs((256 - $_or_24) << 24); - } else { - $_ord_24 = ($_or_24 & 127) << 24; - } - return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24; - } - } diff --git a/libraries/PHPExcel/PHPExcel/Reader/Gnumeric.php b/libraries/PHPExcel/PHPExcel/Reader/Gnumeric.php new file mode 100644 index 000000000..af0b5fe46 --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Reader/Gnumeric.php @@ -0,0 +1,914 @@ +_readDataOnly; + } + + /** + * Set read data only + * Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information. + * Set to false (the default) to advise the Reader to read both data and formatting for cells. + * + * @param boolean $pValue + * + * @return PHPExcel_Reader_Gnumeric + */ + public function setReadDataOnly($pValue = false) { + $this->_readDataOnly = $pValue; + return $this; + } + + /** + * Get which sheets to load + * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null + * indicating that all worksheets in the workbook should be loaded. + * + * @return mixed + */ + public function getLoadSheetsOnly() + { + return $this->_loadSheetsOnly; + } + + /** + * Set which sheets to load + * + * @param mixed $value + * This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name. + * If NULL, then it tells the Reader to read all worksheets in the workbook + * + * @return PHPExcel_Reader_Gnumeric + */ + public function setLoadSheetsOnly($value = null) + { + $this->_loadSheetsOnly = is_array($value) ? + $value : array($value); + return $this; + } + + /** + * Set all sheets to load + * Tells the Reader to load all worksheets from the workbook. + * + * @return PHPExcel_Reader_Gnumeric + */ + public function setLoadAllSheets() + { + $this->_loadSheetsOnly = null; + return $this; + } + + /** + * Read filter + * + * @return PHPExcel_Reader_IReadFilter + */ + public function getReadFilter() { + return $this->_readFilter; + } + + /** + * Set read filter + * + * @param PHPExcel_Reader_IReadFilter $pValue + * @return PHPExcel_Reader_Gnumeric + */ + public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) { + $this->_readFilter = $pValue; + return $this; + } + + /** + * Create a new PHPExcel_Reader_Gnumeric + */ + public function __construct() { + $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter(); + $this->_referenceHelper = PHPExcel_ReferenceHelper::getInstance(); + } + + /** + * Can the current PHPExcel_Reader_IReader read the file? + * + * @param string $pFileName + * @return boolean + */ + public function canRead($pFilename) + { + // Check if gzlib functions are available + if (!function_exists('gzread')) { + return false; + } + + // Check if file exists + if (!file_exists($pFilename)) { + throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); + } + + // Read signature data (first 3 bytes) + $fh = fopen($pFilename, 'r'); + $data = fread($fh, 2); + fclose($fh); + + if ($data != chr(0x1F).chr(0x8B)) { + return false; + } + + return true; + } + + /** + * Loads PHPExcel from file + * + * @param string $pFilename + * @return PHPExcel + * @throws Exception + */ + public function load($pFilename) + { + // Create new PHPExcel + $objPHPExcel = new PHPExcel(); + + // Load into this instance + return $this->loadIntoExisting($pFilename, $objPHPExcel); + } + + private function _gzfileGetContents($filename) { + $file = @gzopen($filename, 'rb'); + if ($file !== false) { + $data = ''; + while (!gzeof($file)) { + $data .= gzread($file, 1024); + } + gzclose($file); + } + return $data; + } + + /** + * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object + * + * @param string $pFilename + * @throws Exception + */ + public function listWorksheetNames($pFilename) + { + // Check if file exists + if (!file_exists($pFilename)) { + throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); + } + + $gFileData = $this->_gzfileGetContents($pFilename); + + $xml = simplexml_load_string($gFileData); + $namespacesMeta = $xml->getNamespaces(true); + + $gnmXML = $xml->children($namespacesMeta['gnm']); + + $worksheetNames = array(); + + foreach($gnmXML->Sheets->Sheet as $sheet) { + $worksheetNames[] = (string) $sheet->Name; + } + + return $worksheetNames; + } + + + /** + * Loads PHPExcel from file into PHPExcel instance + * + * @param string $pFilename + * @param PHPExcel $objPHPExcel + * @return PHPExcel + * @throws Exception + */ + public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel) + { + // Check if file exists + if (!file_exists($pFilename)) { + throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); + } + + $timezoneObj = new DateTimeZone('Europe/London'); + $GMT = new DateTimeZone('UTC'); + + $gFileData = $this->_gzfileGetContents($pFilename); + +// echo '
';
+//		echo htmlentities($gFileData,ENT_QUOTES,'UTF-8');
+//		echo '

'; +// + $xml = simplexml_load_string($gFileData); + $namespacesMeta = $xml->getNamespaces(true); + +// var_dump($namespacesMeta); +// + $gnmXML = $xml->children($namespacesMeta['gnm']); + + $docProps = $objPHPExcel->getProperties(); + // Document Properties are held differently, depending on the version of Gnumeric + if (isset($namespacesMeta['office'])) { + $officeXML = $xml->children($namespacesMeta['office']); + $officeDocXML = $officeXML->{'document-meta'}; + $officeDocMetaXML = $officeDocXML->meta; + + foreach($officeDocMetaXML as $officePropertyData) { + + $officePropertyDC = array(); + if (isset($namespacesMeta['dc'])) { + $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']); + } + foreach($officePropertyDC as $propertyName => $propertyValue) { + $propertyValue = (string) $propertyValue; + switch ($propertyName) { + case 'title' : + $docProps->setTitle(trim($propertyValue)); + break; + case 'subject' : + $docProps->setSubject(trim($propertyValue)); + break; + case 'creator' : + $docProps->setCreator(trim($propertyValue)); + $docProps->setLastModifiedBy(trim($propertyValue)); + break; + case 'date' : + $creationDate = strtotime(trim($propertyValue)); + $docProps->setCreated($creationDate); + $docProps->setModified($creationDate); + break; + case 'description' : + $docProps->setDescription(trim($propertyValue)); + break; + } + } + $officePropertyMeta = array(); + if (isset($namespacesMeta['meta'])) { + $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']); + } + foreach($officePropertyMeta as $propertyName => $propertyValue) { + $attributes = $propertyValue->attributes($namespacesMeta['meta']); + $propertyValue = (string) $propertyValue; + switch ($propertyName) { + case 'keyword' : + $docProps->setKeywords(trim($propertyValue)); + break; + case 'initial-creator' : + $docProps->setCreator(trim($propertyValue)); + $docProps->setLastModifiedBy(trim($propertyValue)); + break; + case 'creation-date' : + $creationDate = strtotime(trim($propertyValue)); + $docProps->setCreated($creationDate); + $docProps->setModified($creationDate); + break; + case 'user-defined' : + list(,$attrName) = explode(':',$attributes['name']); + switch ($attrName) { + case 'publisher' : + $docProps->setCompany(trim($propertyValue)); + break; + case 'category' : + $docProps->setCategory(trim($propertyValue)); + break; + case 'manager' : + $docProps->setManager(trim($propertyValue)); + break; + } + break; + } + } + } + } elseif (isset($gnmXML->Summary)) { + foreach($gnmXML->Summary->Item as $summaryItem) { + $propertyName = $summaryItem->name; + $propertyValue = $summaryItem->{'val-string'}; + switch ($propertyName) { + case 'title' : + $docProps->setTitle(trim($propertyValue)); + break; + case 'comments' : + $docProps->setDescription(trim($propertyValue)); + break; + case 'keywords' : + $docProps->setKeywords(trim($propertyValue)); + break; + case 'category' : + $docProps->setCategory(trim($propertyValue)); + break; + case 'manager' : + $docProps->setManager(trim($propertyValue)); + break; + case 'author' : + $docProps->setCreator(trim($propertyValue)); + $docProps->setLastModifiedBy(trim($propertyValue)); + break; + case 'company' : + $docProps->setCompany(trim($propertyValue)); + break; + } + } + } + + $worksheetID = 0; + foreach($gnmXML->Sheets->Sheet as $sheet) { + $worksheetName = (string) $sheet->Name; +// echo 'Worksheet: ',$worksheetName,'
'; + if ((isset($this->_loadSheetsOnly)) && (!in_array($worksheetName, $this->_loadSheetsOnly))) { + continue; + } + + $maxRow = $maxCol = 0; + + // Create new Worksheet + $objPHPExcel->createSheet(); + $objPHPExcel->setActiveSheetIndex($worksheetID); + $objPHPExcel->getActiveSheet()->setTitle($worksheetName); + + if ((!$this->_readDataOnly) && (isset($sheet->PrintInformation))) { + if (isset($sheet->PrintInformation->Margins)) { + foreach($sheet->PrintInformation->Margins->children('gnm',TRUE) as $key => $margin) { + $marginAttributes = $margin->attributes(); + $marginSize = 72 / 100; // Default + switch($marginAttributes['PrefUnit']) { + case 'mm' : + $marginSize = intval($marginAttributes['Points']) / 100; + break; + } + switch($key) { + case 'top' : + $objPHPExcel->getActiveSheet()->getPageMargins()->setTop($marginSize); + break; + case 'bottom' : + $objPHPExcel->getActiveSheet()->getPageMargins()->setBottom($marginSize); + break; + case 'left' : + $objPHPExcel->getActiveSheet()->getPageMargins()->setLeft($marginSize); + break; + case 'right' : + $objPHPExcel->getActiveSheet()->getPageMargins()->setRight($marginSize); + break; + case 'header' : + $objPHPExcel->getActiveSheet()->getPageMargins()->setHeader($marginSize); + break; + case 'footer' : + $objPHPExcel->getActiveSheet()->getPageMargins()->setFooter($marginSize); + break; + } + } + } + } + + foreach($sheet->Cells->Cell as $cell) { + $cellAttributes = $cell->attributes(); + $row = (int) $cellAttributes->Row + 1; + $column = (int) $cellAttributes->Col; + + if ($row > $maxRow) $maxRow = $row; + if ($column > $maxCol) $maxCol = $column; + + $column = PHPExcel_Cell::stringFromColumnIndex($column); + + // Read cell? + if (!is_null($this->getReadFilter())) { + if (!$this->getReadFilter()->readCell($column, $row, $worksheetName)) { + continue; + } + } + + $ValueType = $cellAttributes->ValueType; + $ExprID = (string) $cellAttributes->ExprID; +// echo 'Cell ',$column,$row,'
'; +// echo 'Type is ',$ValueType,'
'; +// echo 'Value is ',$cell,'
'; + $type = PHPExcel_Cell_DataType::TYPE_FORMULA; + if ($ExprID > '') { + if (((string) $cell) > '') { + + $this->_expressions[$ExprID] = array( 'column' => $cellAttributes->Col, + 'row' => $cellAttributes->Row, + 'formula' => (string) $cell + ); +// echo 'NEW EXPRESSION ',$ExprID,'
'; + } else { + $expression = $this->_expressions[$ExprID]; + + $cell = $this->_referenceHelper->updateFormulaReferences( $expression['formula'], + 'A1', + $cellAttributes->Col - $expression['column'], + $cellAttributes->Row - $expression['row'], + $worksheetName + ); +// echo 'SHARED EXPRESSION ',$ExprID,'
'; +// echo 'New Value is ',$cell,'
'; + } + $type = PHPExcel_Cell_DataType::TYPE_FORMULA; + } else { + switch($ValueType) { + case '10' : // NULL + $type = PHPExcel_Cell_DataType::TYPE_NULL; + break; + case '20' : // Boolean + $type = PHPExcel_Cell_DataType::TYPE_BOOL; + $cell = ($cell == 'TRUE') ? True : False; + break; + case '30' : // Integer + $cell = intval($cell); + case '40' : // Float + $type = PHPExcel_Cell_DataType::TYPE_NUMERIC; + break; + case '50' : // Error + $type = PHPExcel_Cell_DataType::TYPE_ERROR; + break; + case '60' : // String + $type = PHPExcel_Cell_DataType::TYPE_STRING; + break; + case '70' : // Cell Range + case '80' : // Array + } + } + $objPHPExcel->getActiveSheet()->getCell($column.$row)->setValueExplicit($cell,$type); + } + + if ((!$this->_readDataOnly) && (isset($sheet->Objects))) { + foreach($sheet->Objects->children('gnm',TRUE) as $key => $comment) { + $commentAttributes = $comment->attributes(); + // Only comment objects are handled at the moment + if ($commentAttributes->Text) { + $objPHPExcel->getActiveSheet()->getComment( (string)$commentAttributes->ObjectBound ) + ->setAuthor( (string)$commentAttributes->Author ) + ->setText($this->_parseRichText((string)$commentAttributes->Text) ); + } + } + } +// echo '$maxCol=',$maxCol,'; $maxRow=',$maxRow,'
'; +// + foreach($sheet->Styles->StyleRegion as $styleRegion) { + $styleAttributes = $styleRegion->attributes(); +// var_dump($styleAttributes); +// echo '
'; + + if (($styleAttributes['startRow'] <= $maxRow) && + ($styleAttributes['startCol'] <= $maxCol)) { + + $startColumn = PHPExcel_Cell::stringFromColumnIndex($styleAttributes['startCol']); + $startRow = $styleAttributes['startRow'] + 1; + + $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : $styleAttributes['endCol']; + $endColumn = PHPExcel_Cell::stringFromColumnIndex($endColumn); + $endRow = ($styleAttributes['endRow'] > $maxRow) ? $maxRow : $styleAttributes['endRow']; + $endRow += 1; + $cellRange = $startColumn.$startRow.':'.$endColumn.$endRow; +// echo $cellRange,'
'; + + $styleAttributes = $styleRegion->Style->attributes(); +// var_dump($styleAttributes); +// echo '
'; + + // We still set the number format mask for date/time values, even if _readDataOnly is true + if ((!$this->_readDataOnly) || + (PHPExcel_Shared_Date::isDateTimeFormatCode($styleArray['numberformat']['code']))) { + $styleArray = array(); + $styleArray['numberformat']['code'] = (string) $styleAttributes['Format']; + // If _readDataOnly is false, we set all formatting information + if (!$this->_readDataOnly) { + switch($styleAttributes['HAlign']) { + case '1' : + $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL; + break; + case '2' : + $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_LEFT; + break; + case '4' : + $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_RIGHT; + break; + case '8' : + $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_CENTER; + break; + case '16' : + case '64' : + $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS; + break; + case '32' : + $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY; + break; + } + + switch($styleAttributes['VAlign']) { + case '1' : + $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_TOP; + break; + case '2' : + $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_BOTTOM; + break; + case '4' : + $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_CENTER; + break; + case '8' : + $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_JUSTIFY; + break; + } + + $styleArray['alignment']['wrap'] = ($styleAttributes['WrapText'] == '1') ? True : False; + $styleArray['alignment']['shrinkToFit'] = ($styleAttributes['ShrinkToFit'] == '1') ? True : False; + $styleArray['alignment']['indent'] = (intval($styleAttributes["Indent"]) > 0) ? $styleAttributes["indent"] : 0; + + $RGB = self::_parseGnumericColour($styleAttributes["Fore"]); + $styleArray['font']['color']['rgb'] = $RGB; + $RGB = self::_parseGnumericColour($styleAttributes["Back"]); + $shade = $styleAttributes["Shade"]; + if (($RGB != '000000') || ($shade != '0')) { + $styleArray['fill']['color']['rgb'] = $styleArray['fill']['startcolor']['rgb'] = $RGB; + $RGB2 = self::_parseGnumericColour($styleAttributes["PatternColor"]); + $styleArray['fill']['endcolor']['rgb'] = $RGB2; + switch($shade) { + case '1' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_SOLID; + break; + case '2' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR; + break; + case '3' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_GRADIENT_PATH; + break; + case '4' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN; + break; + case '5' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY; + break; + case '6' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID; + break; + case '7' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL; + break; + case '8' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS; + break; + case '9' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKUP; + break; + case '10' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL; + break; + case '11' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625; + break; + case '12' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_GRAY125; + break; + case '13' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN; + break; + case '14' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY; + break; + case '15' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID; + break; + case '16' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL; + break; + case '17' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS; + break; + case '18' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP; + break; + case '19' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL; + break; + case '20' : + $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY; + break; + } + } + + $fontAttributes = $styleRegion->Style->Font->attributes(); +// var_dump($fontAttributes); +// echo '
'; + $styleArray['font']['name'] = (string) $styleRegion->Style->Font; + $styleArray['font']['size'] = intval($fontAttributes['Unit']); + $styleArray['font']['bold'] = ($fontAttributes['Bold'] == '1') ? True : False; + $styleArray['font']['italic'] = ($fontAttributes['Italic'] == '1') ? True : False; + $styleArray['font']['strike'] = ($fontAttributes['StrikeThrough'] == '1') ? True : False; + switch($fontAttributes['Underline']) { + case '1' : + $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_SINGLE; + break; + case '2' : + $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_DOUBLE; + break; + case '3' : + $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING; + break; + case '4' : + $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING; + break; + default : + $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_NONE; + break; + } + switch($fontAttributes['Script']) { + case '1' : + $styleArray['font']['superScript'] = True; + break; + case '-1' : + $styleArray['font']['subScript'] = True; + break; + } + + if (isset($styleRegion->Style->StyleBorder)) { + if (isset($styleRegion->Style->StyleBorder->Top)) { + $styleArray['borders']['top'] = self::_parseBorderAttributes($styleRegion->Style->StyleBorder->Top->attributes()); + } + if (isset($styleRegion->Style->StyleBorder->Bottom)) { + $styleArray['borders']['bottom'] = self::_parseBorderAttributes($styleRegion->Style->StyleBorder->Bottom->attributes()); + } + if (isset($styleRegion->Style->StyleBorder->Left)) { + $styleArray['borders']['left'] = self::_parseBorderAttributes($styleRegion->Style->StyleBorder->Left->attributes()); + } + if (isset($styleRegion->Style->StyleBorder->Right)) { + $styleArray['borders']['right'] = self::_parseBorderAttributes($styleRegion->Style->StyleBorder->Right->attributes()); + } + if ((isset($styleRegion->Style->StyleBorder->Diagonal)) && (isset($styleRegion->Style->StyleBorder->{'Rev-Diagonal'}))) { + $styleArray['borders']['diagonal'] = self::_parseBorderAttributes($styleRegion->Style->StyleBorder->Diagonal->attributes()); + $styleArray['borders']['diagonaldirection'] = PHPExcel_Style_Borders::DIAGONAL_BOTH; + } elseif (isset($styleRegion->Style->StyleBorder->Diagonal)) { + $styleArray['borders']['diagonal'] = self::_parseBorderAttributes($styleRegion->Style->StyleBorder->Diagonal->attributes()); + $styleArray['borders']['diagonaldirection'] = PHPExcel_Style_Borders::DIAGONAL_UP; + } elseif (isset($styleRegion->Style->StyleBorder->{'Rev-Diagonal'})) { + $styleArray['borders']['diagonal'] = self::_parseBorderAttributes($styleRegion->Style->StyleBorder->{'Rev-Diagonal'}->attributes()); + $styleArray['borders']['diagonaldirection'] = PHPExcel_Style_Borders::DIAGONAL_DOWN; + } + } + if (isset($styleRegion->Style->HyperLink)) { + // TO DO + $hyperlink = $styleRegion->Style->HyperLink->attributes(); + } + } +// var_dump($styleArray); +// echo '
'; + $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray); + } + } + } + + if ((!$this->_readDataOnly) && (isset($sheet->Cols))) { + // Column Widths + $columnAttributes = $sheet->Cols->attributes(); + $defaultWidth = $columnAttributes['DefaultSizePts'] / 5.4; + $c = 0; + foreach($sheet->Cols->ColInfo as $columnOverride) { + $columnAttributes = $columnOverride->attributes(); + $column = $columnAttributes['No']; + $columnWidth = $columnAttributes['Unit'] / 5.4; + $hidden = ((isset($columnAttributes['Hidden'])) && ($columnAttributes['Hidden'] == '1')) ? true : false; + $columnCount = (isset($columnAttributes['Count'])) ? $columnAttributes['Count'] : 1; + while ($c < $column) { + $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setWidth($defaultWidth); + ++$c; + } + while (($c < ($column+$columnCount)) && ($c <= $maxCol)) { + $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setWidth($columnWidth); + if ($hidden) { + $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setVisible(false); + } + ++$c; + } + } + while ($c <= $maxCol) { + $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setWidth($defaultWidth); + ++$c; + } + } + + if ((!$this->_readDataOnly) && (isset($sheet->Rows))) { + // Row Heights + $rowAttributes = $sheet->Rows->attributes(); + $defaultHeight = $rowAttributes['DefaultSizePts']; + $r = 0; + + foreach($sheet->Rows->RowInfo as $rowOverride) { + $rowAttributes = $rowOverride->attributes(); + $row = $rowAttributes['No']; + $rowHeight = $rowAttributes['Unit']; + $hidden = ((isset($rowAttributes['Hidden'])) && ($rowAttributes['Hidden'] == '1')) ? true : false; + $rowCount = (isset($rowAttributes['Count'])) ? $rowAttributes['Count'] : 1; + while ($r < $row) { + ++$r; + $objPHPExcel->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight); + } + while (($r < ($row+$rowCount)) && ($r < $maxRow)) { + ++$r; + $objPHPExcel->getActiveSheet()->getRowDimension($r)->setRowHeight($rowHeight); + if ($hidden) { + $objPHPExcel->getActiveSheet()->getRowDimension($r)->setVisible(false); + } + } + } + while ($r < $maxRow) { + ++$r; + $objPHPExcel->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight); + } + } + + // Handle Merged Cells in this worksheet + if (isset($sheet->MergedRegions)) { + foreach($sheet->MergedRegions->Merge as $mergeCells) { + $objPHPExcel->getActiveSheet()->mergeCells($mergeCells); + } + } + + $worksheetID++; + } + + // Loop through definedNames (global named ranges) + if (isset($gnmXML->Names)) { + foreach($gnmXML->Names->Name as $namedRange) { + $name = (string) $namedRange->name; + $range = (string) $namedRange->value; + if (stripos($range, '#REF!') !== false) { + continue; + } + + $range = explode('!',$range); + $range[0] = trim($range[0],"'");; + if ($worksheet = $objPHPExcel->getSheetByName($range[0])) { + $extractedRange = str_replace('$', '', $range[1]); + $objPHPExcel->addNamedRange( new PHPExcel_NamedRange($name, $worksheet, $extractedRange) ); + } + } + } + + + // Return + return $objPHPExcel; + } + + private static function _parseBorderAttributes($borderAttributes) { + $styleArray = array(); + + if (isset($borderAttributes["Color"])) { + $RGB = self::_parseGnumericColour($borderAttributes["Color"]); + $styleArray['color']['rgb'] = $RGB; + } + + switch ($borderAttributes["Style"]) { + case '0' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_NONE; + break; + case '1' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_THIN; + break; + case '2' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUM; + break; + case '4' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_DASHED; + break; + case '5' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_THICK; + break; + case '6' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_DOUBLE; + break; + case '7' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_DOTTED; + break; + case '9' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_DASHDOT; + break; + case '10' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT; + break; + case '11' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_DASHDOTDOT; + break; + case '12' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT; + break; + case '13' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT; + break; + case '3' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_SLANTDASHDOT; + break; + case '8' : + $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHED; + break; + } + return $styleArray; + } + + private function _parseRichText($is = '') { + $value = new PHPExcel_RichText(); + + $value->createText($is); + + return $value; + } + + private static function _parseGnumericColour($gnmColour) { + list($gnmR,$gnmG,$gnmB) = explode(':',$gnmColour); + $gnmR = substr(str_pad($gnmR,4,'0',STR_PAD_RIGHT),0,2); + $gnmG = substr(str_pad($gnmG,4,'0',STR_PAD_RIGHT),0,2); + $gnmB = substr(str_pad($gnmB,4,'0',STR_PAD_RIGHT),0,2); + $RGB = $gnmR.$gnmG.$gnmB; +// echo 'Excel Colour: ',$RGB,'
'; + return $RGB; + } + +} diff --git a/libraries/PHPExcel/PHPExcel/Reader/IReadFilter.php b/libraries/PHPExcel/PHPExcel/Reader/IReadFilter.php index 00fa2e8b5..d5b0cb9c2 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/IReadFilter.php +++ b/libraries/PHPExcel/PHPExcel/Reader/IReadFilter.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ interface PHPExcel_Reader_IReadFilter { diff --git a/libraries/PHPExcel/PHPExcel/Reader/IReader.php b/libraries/PHPExcel/PHPExcel/Reader/IReader.php index e1cdc43bc..d82260a31 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/IReader.php +++ b/libraries/PHPExcel/PHPExcel/Reader/IReader.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ interface PHPExcel_Reader_IReader { diff --git a/libraries/PHPExcel/PHPExcel/Reader/OOCalc.php b/libraries/PHPExcel/PHPExcel/Reader/OOCalc.php index a1ddf91d0..93a376bef 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/OOCalc.php +++ b/libraries/PHPExcel/PHPExcel/Reader/OOCalc.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,44 +33,34 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** - * PHPExcel_Reader_OOCalc + * PHPExcel_Reader_OOCalc * - * @category PHPExcel - * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @category PHPExcel + * @package PHPExcel_Reader + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader { /** - * Read data only? + * Read data only? + * Identifies whether the Reader should only read data values for cells, and ignore any formatting information; + * or whether it should read both data and formatting * - * @var boolean + * @var boolean */ private $_readDataOnly = false; /** - * Restict which sheets should be loaded? + * Restrict which sheets should be loaded? + * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded. * - * @var array + * @var array of string */ private $_loadSheetsOnly = null; - /** - * Sheet index to read - * - * @var int - */ - private $_sheetIndex; - /** * Formats * @@ -87,19 +77,24 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader /** - * Read data only? + * Read data only? + * If this is true, then the Reader will only read data values for cells, it will not read any formatting information. + * If false (the default) it will read data and formatting. * - * @return boolean + * @return boolean */ public function getReadDataOnly() { return $this->_readDataOnly; } /** - * Set read data only + * Set read data only + * Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information. + * Set to false (the default) to advise the Reader to read both data and formatting for cells. * - * @param boolean $pValue - * @return PHPExcel_Reader_Excel2007 + * @param boolean $pValue + * + * @return PHPExcel_Reader_OOCalc */ public function setReadDataOnly($pValue = false) { $this->_readDataOnly = $pValue; @@ -107,9 +102,11 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader } /** - * Get which sheets to load + * Get which sheets to load + * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null + * indicating that all worksheets in the workbook should be loaded. * - * @return mixed + * @return mixed */ public function getLoadSheetsOnly() { @@ -117,10 +114,13 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader } /** - * Set which sheets to load + * Set which sheets to load * - * @param mixed $value - * @return PHPExcel_Reader_Excel2007 + * @param mixed $value + * This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name. + * If NULL, then it tells the Reader to read all worksheets in the workbook + * + * @return PHPExcel_Reader_OOCalc */ public function setLoadSheetsOnly($value = null) { @@ -130,9 +130,10 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader } /** - * Set all sheets to load + * Set all sheets to load + * Tells the Reader to load all worksheets from the workbook. * - * @return PHPExcel_Reader_Excel2007 + * @return PHPExcel_Reader_OOCalc */ public function setLoadAllSheets() { @@ -153,7 +154,7 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader * Set read filter * * @param PHPExcel_Reader_IReadFilter $pValue - * @return PHPExcel_Reader_Excel2007 + * @return PHPExcel_Reader_OOCalc */ public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) { $this->_readFilter = $pValue; @@ -164,7 +165,6 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader * Create a new PHPExcel_Reader_OOCalc */ public function __construct() { - $this->_sheetIndex = 0; $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter(); } @@ -200,6 +200,42 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader return false; } + /** + * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object + * + * @param string $pFilename + * @throws Exception + */ + public function listWorksheetNames($pFilename) + { + // Check if file exists + if (!file_exists($pFilename)) { + throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); + } + + $worksheetNames = array(); + + $zip = new ZipArchive; + if ($zip->open($pFilename) === true) { + + $xml = simplexml_load_string($zip->getFromName("content.xml")); + $namespacesContent = $xml->getNamespaces(true); + + $workbook = $xml->children($namespacesContent['office']); + foreach($workbook->body->spreadsheet as $workbookData) { + $workbookData = $workbookData->children($namespacesContent['table']); + foreach($workbookData->table as $worksheetDataSet) { + $worksheetDataAttributes = $worksheetDataSet->attributes($namespacesContent['table']); + + $worksheetNames[] = $worksheetDataAttributes['name']; + } + } + } + + return $worksheetNames; + } + + /** * Loads PHPExcel from file * @@ -262,8 +298,6 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']); } foreach($officePropertyDC as $propertyName => $propertyValue) { -// echo $propertyName.' = '.$propertyValue.'
'; - switch ($propertyName) { case 'title' : $docProps->setTitle($propertyValue); @@ -273,10 +307,12 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader break; case 'creator' : $docProps->setCreator($propertyValue); + $docProps->setLastModifiedBy($propertyValue); break; case 'date' : $creationDate = strtotime($propertyValue); $docProps->setCreated($creationDate); + $docProps->setModified($creationDate); break; case 'description' : $docProps->setDescription($propertyValue); @@ -289,17 +325,43 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader } foreach($officePropertyMeta as $propertyName => $propertyValue) { $propertyValueAttributes = $propertyValue->attributes($namespacesMeta['meta']); - -// echo $propertyName.' = '.$propertyValue.'
'; -// foreach ($propertyValueAttributes as $key => $value) { -// echo $key.' = '.$value.'
'; -// } -// echo '
'; -// switch ($propertyName) { + case 'initial-creator' : + $docProps->setCreator($propertyValue); + break; case 'keyword' : $docProps->setKeywords($propertyValue); break; + case 'creation-date' : + $creationDate = strtotime($propertyValue); + $docProps->setCreated($creationDate); + break; + case 'user-defined' : + $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING; + foreach ($propertyValueAttributes as $key => $value) { + if ($key == 'name') { + $propertyValueName = (string) $value; + } elseif($key == 'value-type') { + switch ($value) { + case 'date' : + $propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue,'date'); + $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_DATE; + break; + case 'boolean' : + $propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue,'bool'); + $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_BOOLEAN; + break; + case 'float' : + $propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue,'r4'); + $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_FLOAT; + break; + default : + $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING; + } + } + } + $docProps->setCustomProperty($propertyValueName,$propertyValue,$propertyValueType); + break; } } } @@ -349,8 +411,15 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader case 'table-row' : $columnID = 'A'; foreach($rowData as $key => $cellData) { + if (!is_null($this->getReadFilter())) { + if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { + continue; + } + } + // echo ''.$columnID.$rowID.'
'; $cellDataText = $cellData->children($namespacesContent['text']); + $cellDataOffice = $cellData->children($namespacesContent['office']); $cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']); $cellDataTableAttributes = $cellData->attributes($namespacesContent['table']); @@ -370,6 +439,22 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader $hasCalculatedValue = true; } + if (isset($cellDataOffice->annotation)) { +// echo 'Cell has comment
'; + $annotationText = $cellDataOffice->annotation->children($namespacesContent['text']); + $textArray = array(); + foreach($annotationText as $t) { + foreach($t->span as $text) { + $textArray[] = (string)$text; + } + } + $text = implode("\n",$textArray); +// echo $text,'
'; + $objPHPExcel->getActiveSheet()->getComment( $columnID.$rowID ) +// ->setAuthor( $author ) + ->setText($this->_parseRichText($text) ); + } + if (isset($cellDataText->p)) { // echo 'Value Type is '.$cellDataOfficeAttributes['value-type'].'
'; switch ($cellDataOfficeAttributes['value-type']) { @@ -422,9 +507,10 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader // echo 'Formula: '.$cellDataFormula.'
'; $cellDataFormula = substr($cellDataFormula,strpos($cellDataFormula,':=')+1); $temp = explode('"',$cellDataFormula); - foreach($temp as $key => &$value) { + $tKey = false; + foreach($temp as &$value) { // Only replace in alternate array entries (i.e. non-quoted blocks) - if (($key % 2) == 0) { + if ($tKey = !$tKey) { $value = preg_replace('/\[\.(.*):\.(.*)\]/Ui','$1:$2',$value); $value = preg_replace('/\[\.(.*)\]/Ui','$1',$value); $value = PHPExcel_Calculation::_translateSeparator(';',',',$value,$inBraces); @@ -485,23 +571,12 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader return $objPHPExcel; } - /** - * Get sheet index - * - * @return int - */ - public function getSheetIndex() { - return $this->_sheetIndex; + private function _parseRichText($is = '') { + $value = new PHPExcel_RichText(); + + $value->createText($is); + + return $value; } - /** - * Set sheet index - * - * @param int $pValue Sheet index - * @return PHPExcel_Reader_OOCalc - */ - public function setSheetIndex($pValue = 0) { - $this->_sheetIndex = $pValue; - return $this; - } } diff --git a/libraries/PHPExcel/PHPExcel/Reader/SYLK.php b/libraries/PHPExcel/PHPExcel/Reader/SYLK.php index 790aa2f05..5c9830aae 100644 --- a/libraries/PHPExcel/PHPExcel/Reader/SYLK.php +++ b/libraries/PHPExcel/PHPExcel/Reader/SYLK.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,12 +33,6 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } /** @@ -46,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) { * * @category PHPExcel * @package PHPExcel_Reader - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader { @@ -55,35 +49,14 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader * * @var string */ - private $_inputEncoding; - - /** - * Delimiter - * - * @var string - */ - private $_delimiter; - - /** - * Enclosure - * - * @var string - */ - private $_enclosure; - - /** - * Line ending - * - * @var string - */ - private $_lineEnding; + private $_inputEncoding = 'ANSI'; /** * Sheet index to read * * @var int */ - private $_sheetIndex; + private $_sheetIndex = 0; /** * Formats @@ -110,11 +83,6 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader * Create a new PHPExcel_Reader_SYLK */ public function __construct() { - $this->_inputEncoding = 'ANSI'; - $this->_delimiter = ';'; - $this->_enclosure = '"'; - $this->_lineEnding = PHP_EOL; - $this->_sheetIndex = 0; $this->_readFilter = new PHPExcel_Reader_DefaultReadFilter(); } @@ -302,9 +270,10 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader case 'E' : $cellDataFormula = '='.substr($rowDatum,1); // Convert R1C1 style references to A1 style references (but only when not quoted) $temp = explode('"',$cellDataFormula); - foreach($temp as $key => &$value) { + $key = false; + foreach($temp as &$value) { // Only count/replace in alternate array entries - if (($key % 2) == 0) { + if ($key = !$key) { preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/',$value, $cellReferences,PREG_SET_ORDER+PREG_OFFSET_CAPTURE); // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way // through the formula from left to right. Reversing means that we work right to left.through @@ -423,69 +392,6 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader return $objPHPExcel; } - /** - * Get delimiter - * - * @return string - */ - public function getDelimiter() { - return $this->_delimiter; - } - - /** - * Set delimiter - * - * @param string $pValue Delimiter, defaults to , - * @return PHPExcel_Reader_SYLK - */ - public function setDelimiter($pValue = ',') { - $this->_delimiter = $pValue; - return $this; - } - - /** - * Get enclosure - * - * @return string - */ - public function getEnclosure() { - return $this->_enclosure; - } - - /** - * Set enclosure - * - * @param string $pValue Enclosure, defaults to " - * @return PHPExcel_Reader_SYLK - */ - public function setEnclosure($pValue = '"') { - if ($pValue == '') { - $pValue = '"'; - } - $this->_enclosure = $pValue; - return $this; - } - - /** - * Get line ending - * - * @return string - */ - public function getLineEnding() { - return $this->_lineEnding; - } - - /** - * Set line ending - * - * @param string $pValue Line ending, defaults to OS line ending (PHP_EOL) - * @return PHPExcel_Reader_SYLK - */ - public function setLineEnding($pValue = PHP_EOL) { - $this->_lineEnding = $pValue; - return $this; - } - /** * Get sheet index * diff --git a/libraries/PHPExcel/PHPExcel/Reader/Serialized.php b/libraries/PHPExcel/PHPExcel/Reader/Serialized.php deleted file mode 100644 index 04b14f261..000000000 --- a/libraries/PHPExcel/PHPExcel/Reader/Serialized.php +++ /dev/null @@ -1,130 +0,0 @@ -fileSupportsUnserializePHPExcel($pFilename); - } - - /** - * Loads PHPExcel Serialized file - * - * @param string $pFilename - * @return PHPExcel - * @throws Exception - */ - public function load($pFilename) - { - // Check if file exists - if (!file_exists($pFilename)) { - throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); - } - - // Unserialize... First make sure the file supports it! - if (!$this->fileSupportsUnserializePHPExcel($pFilename)) { - throw new Exception("Invalid file format for PHPExcel_Reader_Serialized: " . $pFilename . "."); - } - - return $this->_loadSerialized($pFilename); - } - - /** - * Load PHPExcel Serialized file - * - * @param string $pFilename - * @return PHPExcel - */ - private function _loadSerialized($pFilename) { - $xmlData = simplexml_load_string(file_get_contents("zip://$pFilename#phpexcel.xml")); - $excel = unserialize(base64_decode((string)$xmlData->data)); - - // Update media links - for ($i = 0; $i < $excel->getSheetCount(); ++$i) { - for ($j = 0; $j < $excel->getSheet($i)->getDrawingCollection()->count(); ++$j) { - if ($excel->getSheet($i)->getDrawingCollection()->offsetGet($j) instanceof PHPExcl_Worksheet_BaseDrawing) { - $imgTemp =& $excel->getSheet($i)->getDrawingCollection()->offsetGet($j); - $imgTemp->setPath('zip://' . $pFilename . '#media/' . $imgTemp->getFilename(), false); - } - } - } - - return $excel; - } - - /** - * Does a file support UnserializePHPExcel ? - * - * @param string $pFilename - * @throws Exception - * @return boolean - */ - public function fileSupportsUnserializePHPExcel($pFilename = '') { - // Check if file exists - if (!file_exists($pFilename)) { - throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); - } - - // File exists, does it contain phpexcel.xml? - return PHPExcel_Shared_File::file_exists("zip://$pFilename#phpexcel.xml"); - } -} diff --git a/libraries/PHPExcel/PHPExcel/ReferenceHelper.php b/libraries/PHPExcel/PHPExcel/ReferenceHelper.php index 7a37ed0da..74a12d20a 100644 --- a/libraries/PHPExcel/PHPExcel/ReferenceHelper.php +++ b/libraries/PHPExcel/PHPExcel/ReferenceHelper.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_ReferenceHelper { @@ -137,7 +137,8 @@ class PHPExcel_ReferenceHelper if ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA) { // Formula should be adjusted $pSheet->getCell($newCoordinates) - ->setValue($this->updateFormulaReferences($cell->getValue(), $pBefore, $pNumCols, $pNumRows, $pSheet->getTitle())); + ->setValue($this->updateFormulaReferences($cell->getValue(), + $pBefore, $pNumCols, $pNumRows, $pSheet->getTitle())); } else { // Formula should not be adjusted $pSheet->getCell($newCoordinates)->setValue($cell->getValue()); @@ -145,6 +146,16 @@ class PHPExcel_ReferenceHelper // Clear the original cell $pSheet->getCell($cell->getCoordinate())->setValue(''); + + } else { + /* We don't need to update styles for rows/columns before our insertion position, + but we do still need to adjust any formulae in those cells */ + if ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA) { + // Formula should be adjusted + $cell->setValue($this->updateFormulaReferences($cell->getValue(), + $pBefore, $pNumCols, $pNumRows, $pSheet->getTitle())); + } + } } @@ -248,6 +259,14 @@ class PHPExcel_ReferenceHelper } } + // Update worksheet: comments + $aComments = $pSheet->getComments(); + $aNewComments = array(); // the new array of all comments + foreach ($aComments as $key => &$value) { + $newReference = $this->updateCellReference($key, $pBefore, $pNumCols, $pNumRows); + $aNewComments[$newReference] = $value; + } + $pSheet->setComments($aNewComments); // replace the comments array // Update worksheet: hyperlinks $aHyperlinkCollection = array_reverse($pSheet->getHyperlinkCollection(), true); @@ -348,9 +367,10 @@ class PHPExcel_ReferenceHelper public function updateFormulaReferences($pFormula = '', $pBefore = 'A1', $pNumCols = 0, $pNumRows = 0, $sheetName = '') { // Update cell references in the formula $formulaBlocks = explode('"',$pFormula); - foreach($formulaBlocks as $i => &$formulaBlock) { - // Ignore blocks that were enclosed in quotes (even entries in the $formulaBlocks array after the explode) - if (($i % 2) == 0) { + $i = false; + foreach($formulaBlocks as &$formulaBlock) { + // Ignore blocks that were enclosed in quotes (alternating entries in the $formulaBlocks array after the explode) + if ($i = !$i) { $adjustCount = 0; $newCellTokens = $cellTokens = array(); // Search for row ranges (e.g. 'Sheet1'!3:5 or 3:5) with or without $ absolutes (e.g. $3:5) @@ -525,7 +545,7 @@ class PHPExcel_ReferenceHelper /** * Update cell range * - * @param string $pCellRange Cell range + * @param string $pCellRange Cell range (e.g. 'B2:D4', 'B:C' or '2:3') * @param int $pBefore Insert before this one * @param int $pNumCols Number of columns to increment * @param int $pNumRows Number of rows to increment @@ -536,9 +556,19 @@ class PHPExcel_ReferenceHelper if (strpos($pCellRange,':') !== false || strpos($pCellRange, ',') !== false) { // Update range $range = PHPExcel_Cell::splitRange($pCellRange); - for ($i = 0; $i < count($range); ++$i) { - for ($j = 0; $j < count($range[$i]); ++$j) { - $range[$i][$j] = $this->_updateSingleCellReference($range[$i][$j], $pBefore, $pNumCols, $pNumRows); + $ic = count($range); + for ($i = 0; $i < $ic; ++$i) { + $jc = count($range[$i]); + for ($j = 0; $j < $jc; ++$j) { + if (ctype_alpha($range[$i][$j])) { + $r = PHPExcel_Cell::coordinateFromString($this->_updateSingleCellReference($range[$i][$j].'1', $pBefore, $pNumCols, $pNumRows)); + $range[$i][$j] = $r[0]; + } elseif(ctype_digit($range[$i][$j])) { + $r = PHPExcel_Cell::coordinateFromString($this->_updateSingleCellReference('A'.$range[$i][$j], $pBefore, $pNumCols, $pNumRows)); + $range[$i][$j] = $r[1]; + } else { + $range[$i][$j] = $this->_updateSingleCellReference($range[$i][$j], $pBefore, $pNumCols, $pNumRows); + } } } @@ -562,29 +592,17 @@ class PHPExcel_ReferenceHelper private function _updateSingleCellReference($pCellReference = 'A1', $pBefore = 'A1', $pNumCols = 0, $pNumRows = 0) { if (strpos($pCellReference, ':') === false && strpos($pCellReference, ',') === false) { // Get coordinates of $pBefore - $beforeColumn = 'A'; - $beforeRow = 1; list($beforeColumn, $beforeRow) = PHPExcel_Cell::coordinateFromString( $pBefore ); - // Get coordinates - $newColumn = 'A'; - $newRow = 1; + // Get coordinates of $pCellReference list($newColumn, $newRow) = PHPExcel_Cell::coordinateFromString( $pCellReference ); - // Make sure the reference can be used - if ($newColumn == '' && $newRow == '') - { - return $pCellReference; - } - // Verify which parts should be updated - $updateColumn = (PHPExcel_Cell::columnIndexFromString($newColumn) >= PHPExcel_Cell::columnIndexFromString($beforeColumn)) - && (strpos($newColumn, '$') === false) - && (strpos($beforeColumn, '$') === false); + $updateColumn = (($newColumn{0} != '$') && ($beforeColumn{0} != '$') && + PHPExcel_Cell::columnIndexFromString($newColumn) >= PHPExcel_Cell::columnIndexFromString($beforeColumn)); - $updateRow = ($newRow >= $beforeRow) - && (strpos($newRow, '$') === false) - && (strpos($beforeRow, '$') === false); + $updateRow = (($newRow{0} != '$') && ($beforeRow{0} != '$') && + $newRow >= $beforeRow); // Create new column reference if ($updateColumn) { diff --git a/libraries/PHPExcel/PHPExcel/RichText.php b/libraries/PHPExcel/PHPExcel/RichText.php index 588e64356..57d3ce4d1 100644 --- a/libraries/PHPExcel/PHPExcel/RichText.php +++ b/libraries/PHPExcel/PHPExcel/RichText.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_RichText implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/RichText/ITextElement.php b/libraries/PHPExcel/PHPExcel/RichText/ITextElement.php index 3f1aa7a3e..e355f8bb2 100644 --- a/libraries/PHPExcel/PHPExcel/RichText/ITextElement.php +++ b/libraries/PHPExcel/PHPExcel/RichText/ITextElement.php @@ -18,9 +18,9 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -29,7 +29,7 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ interface PHPExcel_RichText_ITextElement { diff --git a/libraries/PHPExcel/PHPExcel/RichText/Run.php b/libraries/PHPExcel/PHPExcel/RichText/Run.php index aac76763f..55b592702 100644 --- a/libraries/PHPExcel/PHPExcel/RichText/Run.php +++ b/libraries/PHPExcel/PHPExcel/RichText/Run.php @@ -18,9 +18,9 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -29,7 +29,7 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_RichText_Run extends PHPExcel_RichText_TextElement implements PHPExcel_RichText_ITextElement { diff --git a/libraries/PHPExcel/PHPExcel/RichText/TextElement.php b/libraries/PHPExcel/PHPExcel/RichText/TextElement.php index f5ce8e041..a9a2c05b1 100644 --- a/libraries/PHPExcel/PHPExcel/RichText/TextElement.php +++ b/libraries/PHPExcel/PHPExcel/RichText/TextElement.php @@ -18,9 +18,9 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -29,7 +29,7 @@ * * @category PHPExcel * @package PHPExcel_RichText - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_RichText_TextElement implements PHPExcel_RichText_ITextElement { diff --git a/libraries/PHPExcel/PHPExcel/Settings.php b/libraries/PHPExcel/PHPExcel/Settings.php index 52d788056..f1967cd1a 100644 --- a/libraries/PHPExcel/PHPExcel/Settings.php +++ b/libraries/PHPExcel/PHPExcel/Settings.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Settings - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** PHPExcel root directory */ @@ -32,17 +32,45 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } class PHPExcel_Settings { + /** constants */ + const PCLZIP = 'PHPExcel_Shared_ZipArchive'; + const ZIPARCHIVE = 'ZipArchive'; + + + private static $_zipClass = self::ZIPARCHIVE; + + + /** + * Set the Zip Class to use (PCLZip or ZipArchive) + * + * @param string $zipClass PHPExcel_Settings::PCLZip or PHPExcel_Settings::ZipArchive + * @return boolean Success or failure + */ + public static function setZipClass($zipClass) { + if (($zipClass == self::PCLZIP) || + ($zipClass == self::ZIPARCHIVE)) { + self::$_zipClass = $zipClass; + return True; + } + return False; + } // function setZipClass() + + + /** + * Return the Zip Class to use (PCLZip or ZipArchive) + * + * @return string Zip Class to use - PHPExcel_Settings::PCLZip or PHPExcel_Settings::ZipArchive + */ + public static function getZipClass() { + return self::$_zipClass; + } // function getZipClass() + + public static function getCacheStorageMethod() { return PHPExcel_CachedObjectStorageFactory::$_cacheStorageMethod; } // function getCacheStorageMethod() diff --git a/libraries/PHPExcel/PHPExcel/Shared/CodePage.php b/libraries/PHPExcel/PHPExcel/Shared/CodePage.php index f20983858..7c8854b86 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/CodePage.php +++ b/libraries/PHPExcel/PHPExcel/Shared/CodePage.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_CodePage { @@ -46,46 +46,47 @@ class PHPExcel_Shared_CodePage public static function NumberToName($codePage = '1252') { switch ($codePage) { - case 367: return 'ASCII'; break; // ASCII - case 437: return 'CP437'; break; //OEM US + case 367: return 'ASCII'; break; // ASCII + case 437: return 'CP437'; break; // OEM US case 720: throw new Exception('Code page 720 not supported.'); - break; //OEM Arabic - case 737: return 'CP737'; break; //OEM Greek - case 775: return 'CP775'; break; //OEM Baltic - case 850: return 'CP850'; break; //OEM Latin I - case 852: return 'CP852'; break; //OEM Latin II (Central European) - case 855: return 'CP855'; break; //OEM Cyrillic - case 857: return 'CP857'; break; //OEM Turkish - case 858: return 'CP858'; break; //OEM Multilingual Latin I with Euro - case 860: return 'CP860'; break; //OEM Portugese - case 861: return 'CP861'; break; //OEM Icelandic - case 862: return 'CP862'; break; //OEM Hebrew - case 863: return 'CP863'; break; //OEM Canadian (French) - case 864: return 'CP864'; break; //OEM Arabic - case 865: return 'CP865'; break; //OEM Nordic - case 866: return 'CP866'; break; //OEM Cyrillic (Russian) - case 869: return 'CP869'; break; //OEM Greek (Modern) - case 874: return 'CP874'; break; //ANSI Thai - case 932: return 'CP932'; break; //ANSI Japanese Shift-JIS - case 936: return 'CP936'; break; //ANSI Chinese Simplified GBK - case 949: return 'CP949'; break; //ANSI Korean (Wansung) - case 950: return 'CP950'; break; //ANSI Chinese Traditional BIG5 - case 1200: return 'UTF-16LE'; break; //UTF-16 (BIFF8) - case 1250: return 'CP1250'; break; // ANSI Latin II (Central European) - case 1251: return 'CP1251'; break; //ANSI Cyrillic - case 1252: return 'CP1252'; break; //ANSI Latin I (BIFF4-BIFF7) - case 1253: return 'CP1253'; break; //ANSI Greek - case 1254: return 'CP1254'; break; //ANSI Turkish - case 1255: return 'CP1255'; break; //ANSI Hebrew - case 1256: return 'CP1256'; break; //ANSI Arabic - case 1257: return 'CP1257'; break; //ANSI Baltic - case 1258: return 'CP1258'; break; //ANSI Vietnamese - case 1361: return 'CP1361'; break; //ANSI Korean (Johab) - case 10000: return 'MAC'; break; //Apple Roman - case 32768: return 'MAC'; break; //Apple Roman + break; // OEM Arabic + case 737: return 'CP737'; break; // OEM Greek + case 775: return 'CP775'; break; // OEM Baltic + case 850: return 'CP850'; break; // OEM Latin I + case 852: return 'CP852'; break; // OEM Latin II (Central European) + case 855: return 'CP855'; break; // OEM Cyrillic + case 857: return 'CP857'; break; // OEM Turkish + case 858: return 'CP858'; break; // OEM Multilingual Latin I with Euro + case 860: return 'CP860'; break; // OEM Portugese + case 861: return 'CP861'; break; // OEM Icelandic + case 862: return 'CP862'; break; // OEM Hebrew + case 863: return 'CP863'; break; // OEM Canadian (French) + case 864: return 'CP864'; break; // OEM Arabic + case 865: return 'CP865'; break; // OEM Nordic + case 866: return 'CP866'; break; // OEM Cyrillic (Russian) + case 869: return 'CP869'; break; // OEM Greek (Modern) + case 874: return 'CP874'; break; // ANSI Thai + case 932: return 'CP932'; break; // ANSI Japanese Shift-JIS + case 936: return 'CP936'; break; // ANSI Chinese Simplified GBK + case 949: return 'CP949'; break; // ANSI Korean (Wansung) + case 950: return 'CP950'; break; // ANSI Chinese Traditional BIG5 + case 1200: return 'UTF-16LE'; break; // UTF-16 (BIFF8) + case 1250: return 'CP1250'; break; // ANSI Latin II (Central European) + case 1251: return 'CP1251'; break; // ANSI Cyrillic + case 0: // CodePage is not always correctly set when the xls file was saved by Apple's Numbers program + case 1252: return 'CP1252'; break; // ANSI Latin I (BIFF4-BIFF7) + case 1253: return 'CP1253'; break; // ANSI Greek + case 1254: return 'CP1254'; break; // ANSI Turkish + case 1255: return 'CP1255'; break; // ANSI Hebrew + case 1256: return 'CP1256'; break; // ANSI Arabic + case 1257: return 'CP1257'; break; // ANSI Baltic + case 1258: return 'CP1258'; break; // ANSI Vietnamese + case 1361: return 'CP1361'; break; // ANSI Korean (Johab) + case 10000: return 'MAC'; break; // Apple Roman + case 32768: return 'MAC'; break; // Apple Roman case 32769: throw new Exception('Code page 32769 not supported.'); - break; //ANSI Latin I (BIFF2-BIFF3) - case 65001: return 'UTF-8'; break; //Unicode (UTF-8) + break; // ANSI Latin I (BIFF2-BIFF3) + case 65001: return 'UTF-8'; break; // Unicode (UTF-8) } throw new Exception('Unknown codepage: ' . $codePage); diff --git a/libraries/PHPExcel/PHPExcel/Shared/Date.php b/libraries/PHPExcel/PHPExcel/Shared/Date.php index 334e8df95..16cf6a19e 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Date.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Date.php @@ -3,7 +3,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,9 +21,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -32,7 +32,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Date { @@ -220,7 +220,7 @@ class PHPExcel_Shared_Date } // function isDateTimeFormat() - private static $possibleDateFormatCharacters = 'ymdHis'; + private static $possibleDateFormatCharacters = 'ymdHs'; /** * Is a given number format code a date/time? @@ -256,8 +256,24 @@ class PHPExcel_Shared_Date return true; } + // Typically number, currency or accounting (or occasionally fraction) formats + if ((substr($pFormatCode,0,1) == '_') || (substr($pFormatCode,0,2) == '0 ')) { + return false; + } // Try checking for any of the date formatting characters that don't appear within square braces if (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$pFormatCode)) { + // We might also have a format mask containing quoted strings... + // we don't want to test for any of our characters within the quoted blocks + if (strpos($pFormatCode,'"') !== false) { + $i = false; + foreach(explode('"',$pFormatCode) as $subVal) { + // Only test in alternate array entries (the non-quoted blocks) + if (($i = !$i) && (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$subVal))) { + return true; + } + } + return false; + } return true; } @@ -273,31 +289,27 @@ class PHPExcel_Shared_Date * @return float|false Excel date/time serial value */ public static function stringToExcel($dateValue = '') { - // restrict to dates and times like these because date_parse accepts too many strings - // '2009-12-31' - // '2009-12-31 15:59' - // '2009-12-31 15:59:10' - if (!preg_match('/^\d{4}\-\d{1,2}\-\d{1,2}( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/', $dateValue)) { + if (strlen($dateValue) < 2) return false; + if (!preg_match('/^(\d{1,4}[ \.\/\-][A-Z]{3,9}([ \.\/\-]\d{1,4})?|[A-Z]{3,9}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?|\d{1,4}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?)( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/iu', $dateValue)) + return false; + + $dateValueNew = PHPExcel_Calculation_DateTime::DATEVALUE($dateValue); + + if ($dateValueNew === PHPExcel_Calculation_Functions::VALUE()) { + return false; + } else { + if (strpos($dateValue, ':') !== false) { + $timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($dateValue); + if ($timeValue === PHPExcel_Calculation_Functions::VALUE()) { + return false; + } + $dateValueNew += $timeValue; + } + return $dateValueNew; } - // now try with date_parse - $PHPDateArray = date_parse($dateValue); - if ($PHPDateArray['error_count'] == 0) { - $year = $PHPDateArray['year'] !== false ? $PHPDateArray['year'] : self::getExcelCalendar(); - $month = $PHPDateArray['month'] !== false ? $PHPDateArray['month'] : 1; - $day = $PHPDateArray['day'] !== false ? $PHPDateArray['day'] : 0; - $hour = $PHPDateArray['hour'] !== false ? $PHPDateArray['hour'] : 0; - $minute = $PHPDateArray['minute'] !== false ? $PHPDateArray['minute'] : 0; - $second = $PHPDateArray['second'] !== false ? $PHPDateArray['second'] : 0; - - $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day, $hour, $minute, $second); - - return $excelDateValue; - } - - return false; } } diff --git a/libraries/PHPExcel/PHPExcel/Shared/Drawing.php b/libraries/PHPExcel/PHPExcel/Shared/Drawing.php index a24f96323..3367f272b 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Drawing.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Drawing.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Drawing { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher.php b/libraries/PHPExcel/PHPExcel/Shared/Escher.php index 11c19b2e1..554709607 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer.php b/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer.php index 6cbd2f025..7e17e464a 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher_DgContainer { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php b/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php index 919cf1af4..c11d76571 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher_DgContainer_SpgrContainer { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php b/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php index 454b7ee53..a3bd3cd65 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer.php b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer.php index 61eab5dee..39b57d020 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher_DggContainer { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php index 6040fb280..8ac8f556a 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher_DggContainer_BstoreContainer { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php index 00ccb6d06..9b31bb5e2 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php index 7f13632e4..4a6d4e4c4 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Escher - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Excel5.php b/libraries/PHPExcel/PHPExcel/Shared/Excel5.php index 6469c5263..f6bced503 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Excel5.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Excel5.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** @@ -30,7 +30,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Excel5 { diff --git a/libraries/PHPExcel/PHPExcel/Shared/File.php b/libraries/PHPExcel/PHPExcel/Shared/File.php index 23169ce8a..75532f6c7 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/File.php +++ b/libraries/PHPExcel/PHPExcel/Shared/File.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_File { diff --git a/libraries/PHPExcel/PHPExcel/Shared/Font.php b/libraries/PHPExcel/PHPExcel/Shared/Font.php index 24d78be61..a0535688a 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/Font.php +++ b/libraries/PHPExcel/PHPExcel/Shared/Font.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_Font { diff --git a/libraries/PHPExcel/PHPExcel/Shared/JAMA/LUDecomposition.php b/libraries/PHPExcel/PHPExcel/Shared/JAMA/LUDecomposition.php index 4fd43f91f..6c797a6ce 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/JAMA/LUDecomposition.php +++ b/libraries/PHPExcel/PHPExcel/Shared/JAMA/LUDecomposition.php @@ -18,7 +18,10 @@ * @version 1.1 * @license PHP v3.0 */ -class LUDecomposition { +class PHPExcel_Shared_JAMA_LUDecomposition { + + const MatrixSingularException = "Can only perform operation on singular matrix."; + const MatrixSquareException = "Mismatched Row dimension"; /** * Decomposition storage @@ -58,9 +61,9 @@ class LUDecomposition { * @return Structure to access L, U and piv. */ public function __construct($A) { - if ($A instanceof Matrix) { + if ($A instanceof PHPExcel_Shared_JAMA_Matrix) { // Use a "left-looking", dot-product, Crout/Doolittle algorithm. - $this->LU = $A->getArrayCopy(); + $this->LU = $A->getArray(); $this->m = $A->getRowDimension(); $this->n = $A->getColumnDimension(); for ($i = 0; $i < $this->m; ++$i) { @@ -112,7 +115,7 @@ class LUDecomposition { } } } else { - throw new Exception(JAMAError(ArgumentTypeException)); + throw new Exception(PHPExcel_Shared_JAMA_Matrix::ArgumentTypeException); } } // function __construct() @@ -134,7 +137,7 @@ class LUDecomposition { } } } - return new Matrix($L); + return new PHPExcel_Shared_JAMA_Matrix($L); } // function getL() @@ -153,7 +156,7 @@ class LUDecomposition { } } } - return new Matrix($U); + return new PHPExcel_Shared_JAMA_Matrix($U); } // function getU() @@ -205,7 +208,7 @@ class LUDecomposition { } return $d; } else { - throw new Exception(JAMAError(MatrixDimensionException)); + throw new Exception(PHPExcel_Shared_JAMA_Matrix::MatrixDimensionException); } } // function det() @@ -245,11 +248,11 @@ class LUDecomposition { } return $X; } else { - throw new Exception(JAMAError(MatrixSingularException)); + throw new Exception(self::MatrixSingularException); } } else { - throw new Exception(JAMAError(MatrixSquareException)); + throw new Exception(self::MatrixSquareException); } } // function solve() -} // class LUDecomposition +} // class PHPExcel_Shared_JAMA_LUDecomposition diff --git a/libraries/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php b/libraries/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php index c168567a3..aae40e4c5 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php +++ b/libraries/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php @@ -3,9 +3,6 @@ * @package JAMA */ -define('RAND_MAX', mt_getrandmax()); -define('RAND_MIN', 0); - /** PHPExcel root directory */ if (!defined('PHPEXCEL_ROOT')) { /** @@ -13,23 +10,8 @@ if (!defined('PHPEXCEL_ROOT')) { */ define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../../'); require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); - PHPExcel_Autoloader::Register(); - PHPExcel_Shared_ZipStreamWrapper::register(); - // check mbstring.func_overload - if (ini_get('mbstring.func_overload') & 2) { - throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); - } } -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/utils/Error.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/utils/Maths.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/CholeskyDecomposition.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/LUDecomposition.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/QRDecomposition.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/EigenvalueDecomposition.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/SingularValueDecomposition.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/String.php'; -require_once PHPEXCEL_ROOT . 'PHPExcel/Calculation/Functions.php'; /* * Matrix class @@ -42,7 +24,14 @@ require_once PHPEXCEL_ROOT . 'PHPExcel/Calculation/Functions.php'; * @license PHP v3.0 * @see http://math.nist.gov/javanumerics/jama/ */ -class Matrix { +class PHPExcel_Shared_JAMA_Matrix { + + + const PolymorphicArgumentException = "Invalid argument pattern for polymorphic function."; + const ArgumentTypeException = "Invalid argument type."; + const ArgumentBoundsException = "Invalid argument range."; + const MatrixDimensionException = "Matrix dimensions are not equal."; + const ArrayLengthException = "Array length must be a multiple of m."; /** * Matrix storage @@ -80,6 +69,12 @@ class Matrix { $match = implode(",", array_map('gettype', $args)); switch($match) { + //Rectangular matrix - m x n initialized from 2D array + case 'array': + $this->m = count($args[0]); + $this->n = count($args[0][0]); + $this->A = $args[0]; + break; //Square matrix - n x n case 'integer': $this->m = $args[0]; @@ -92,30 +87,6 @@ class Matrix { $this->n = $args[1]; $this->A = array_fill(0, $this->m, array_fill(0, $this->n, 0)); break; - //Rectangular matrix constant-filled - m x n filled with c - case 'integer,integer,integer': - $this->m = $args[0]; - $this->n = $args[1]; - $this->A = array_fill(0, $this->m, array_fill(0, $this->n, $args[2])); - break; - //Rectangular matrix constant-filled - m x n filled with c - case 'integer,integer,double': - $this->m = $args[0]; - $this->n = $args[1]; - $this->A = array_fill(0, $this->m, array_fill(0, $this->n, $args[2])); - break; - //Rectangular matrix - m x n initialized from 2D array - case 'array': - $this->m = count($args[0]); - $this->n = count($args[0][0]); - $this->A = $args[0]; - break; - //Rectangular matrix - m x n initialized from 2D array - case 'array,integer,integer': - $this->m = $args[1]; - $this->n = $args[2]; - $this->A = $args[0]; - break; //Rectangular matrix - m x n initialized from packed array case 'array,integer': $this->m = $args[1]; @@ -131,15 +102,15 @@ class Matrix { } } } else { - throw new Exception(JAMAError(ArrayLengthException)); + throw new Exception(self::ArrayLengthException); } break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function __construct() @@ -154,73 +125,6 @@ class Matrix { } // function getArray() - /** - * getArrayCopy - * - * @return array Matrix array copy - */ - public function getArrayCopy() { - return $this->A; - } // function getArrayCopy() - - - /** - * constructWithCopy - * Construct a matrix from a copy of a 2-D array. - * - * @param double A[][] Two-dimensional array of doubles. - * @exception IllegalArgumentException All rows must have the same length - */ - public function constructWithCopy($A) { - $this->m = count($A); - $this->n = count($A[0]); - $newCopyMatrix = new Matrix($this->m, $this->n); - for ($i = 0; $i < $this->m; ++$i) { - if (count($A[$i]) != $this->n) { - throw new Exception(JAMAError(RowLengthException)); - } - for ($j = 0; $j < $this->n; ++$j) { - $newCopyMatrix->A[$i][$j] = $A[$i][$j]; - } - } - return $newCopyMatrix; - } // function constructWithCopy() - - - /** - * getColumnPackedCopy - * - * Get a column-packed array - * @return array Column-packed matrix array - */ - public function getColumnPackedCopy() { - $P = array(); - for($i = 0; $i < $this->m; ++$i) { - for($j = 0; $j < $this->n; ++$j) { - array_push($P, $this->A[$j][$i]); - } - } - return $P; - } // function getColumnPackedCopy() - - - /** - * getRowPackedCopy - * - * Get a row-packed array - * @return array Row-packed matrix array - */ - public function getRowPackedCopy() { - $P = array(); - for($i = 0; $i < $this->m; ++$i) { - for($j = 0; $j < $this->n; ++$j) { - array_push($P, $this->A[$i][$j]); - } - } - return $P; - } // function getRowPackedCopy() - - /** * getRowDimension * @@ -273,9 +177,9 @@ class Matrix { //A($i0...; $j0...) case 'integer,integer': list($i0, $j0) = $args; - if ($i0 >= 0) { $m = $this->m - $i0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if ($j0 >= 0) { $n = $this->n - $j0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - $R = new Matrix($m, $n); + if ($i0 >= 0) { $m = $this->m - $i0; } else { throw new Exception(self::ArgumentBoundsException); } + if ($j0 >= 0) { $n = $this->n - $j0; } else { throw new Exception(self::ArgumentBoundsException); } + $R = new PHPExcel_Shared_JAMA_Matrix($m, $n); for($i = $i0; $i < $this->m; ++$i) { for($j = $j0; $j < $this->n; ++$j) { $R->set($i, $j, $this->A[$i][$j]); @@ -286,9 +190,9 @@ class Matrix { //A($i0...$iF; $j0...$jF) case 'integer,integer,integer,integer': list($i0, $iF, $j0, $jF) = $args; - if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) { $m = $iF - $i0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if (($jF > $j0) && ($this->n >= $jF) && ($j0 >= 0)) { $n = $jF - $j0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - $R = new Matrix($m+1, $n+1); + if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) { $m = $iF - $i0; } else { throw new Exception(self::ArgumentBoundsException); } + if (($jF > $j0) && ($this->n >= $jF) && ($j0 >= 0)) { $n = $jF - $j0; } else { throw new Exception(self::ArgumentBoundsException); } + $R = new PHPExcel_Shared_JAMA_Matrix($m+1, $n+1); for($i = $i0; $i <= $iF; ++$i) { for($j = $j0; $j <= $jF; ++$j) { $R->set($i - $i0, $j - $j0, $this->A[$i][$j]); @@ -299,9 +203,9 @@ class Matrix { //$R = array of row indices; $C = array of column indices case 'array,array': list($RL, $CL) = $args; - if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - $R = new Matrix($m, $n); + if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(self::ArgumentBoundsException); } + if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(self::ArgumentBoundsException); } + $R = new PHPExcel_Shared_JAMA_Matrix($m, $n); for($i = 0; $i < $m; ++$i) { for($j = 0; $j < $n; ++$j) { $R->set($i - $i0, $j - $j0, $this->A[$RL[$i]][$CL[$j]]); @@ -312,9 +216,9 @@ class Matrix { //$RL = array of row indices; $CL = array of column indices case 'array,array': list($RL, $CL) = $args; - if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - $R = new Matrix($m, $n); + if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(self::ArgumentBoundsException); } + if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(self::ArgumentBoundsException); } + $R = new PHPExcel_Shared_JAMA_Matrix($m, $n); for($i = 0; $i < $m; ++$i) { for($j = 0; $j < $n; ++$j) { $R->set($i, $j, $this->A[$RL[$i]][$CL[$j]]); @@ -325,9 +229,9 @@ class Matrix { //A($i0...$iF); $CL = array of column indices case 'integer,integer,array': list($i0, $iF, $CL) = $args; - if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) { $m = $iF - $i0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - $R = new Matrix($m, $n); + if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) { $m = $iF - $i0; } else { throw new Exception(self::ArgumentBoundsException); } + if (count($CL) > 0) { $n = count($CL); } else { throw new Exception(self::ArgumentBoundsException); } + $R = new PHPExcel_Shared_JAMA_Matrix($m, $n); for($i = $i0; $i < $iF; ++$i) { for($j = 0; $j < $n; ++$j) { $R->set($i - $i0, $j, $this->A[$RL[$i]][$j]); @@ -338,9 +242,9 @@ class Matrix { //$RL = array of row indices case 'array,integer,integer': list($RL, $j0, $jF) = $args; - if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if (($jF >= $j0) && ($this->n >= $jF) && ($j0 >= 0)) { $n = $jF - $j0; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - $R = new Matrix($m, $n+1); + if (count($RL) > 0) { $m = count($RL); } else { throw new Exception(self::ArgumentBoundsException); } + if (($jF >= $j0) && ($this->n >= $jF) && ($j0 >= 0)) { $n = $jF - $j0; } else { throw new Exception(self::ArgumentBoundsException); } + $R = new PHPExcel_Shared_JAMA_Matrix($m, $n+1); for($i = 0; $i < $m; ++$i) { for($j = $j0; $j <= $jF; ++$j) { $R->set($i, $j - $j0, $this->A[$RL[$i]][$j]); @@ -349,61 +253,15 @@ class Matrix { return $R; break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function getMatrix() - /** - * setMatrix - * - * Set a submatrix - * @param int $i0 Initial row index - * @param int $j0 Initial column index - * @param mixed $S Matrix/Array submatrix - * ($i0, $j0, $S) $S = Matrix - * ($i0, $j0, $S) $S = Array - */ - public function setMatrix() { - if (func_num_args() > 0) { - $args = func_get_args(); - $match = implode(",", array_map('gettype', $args)); - - switch($match) { - case 'integer,integer,object': - if ($args[2] instanceof Matrix) { $M = $args[2]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } - if (($args[0] + $M->m) <= $this->m) { $i0 = $args[0]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if (($args[1] + $M->n) <= $this->n) { $j0 = $args[1]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - for($i = $i0; $i < $i0 + $M->m; ++$i) { - for($j = $j0; $j < $j0 + $M->n; ++$j) { - $this->A[$i][$j] = $M->get($i - $i0, $j - $j0); - } - } - break; - case 'integer,integer,array': - $M = new Matrix($args[2]); - if (($args[0] + $M->m) <= $this->m) { $i0 = $args[0]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - if (($args[1] + $M->n) <= $this->n) { $j0 = $args[1]; } else { throw new Exception(JAMAError(ArgumentBoundsException)); } - for($i = $i0; $i < $i0 + $M->m; ++$i) { - for($j = $j0; $j < $j0 + $M->n; ++$j) { - $this->A[$i][$j] = $M->get($i - $i0, $j - $j0); - } - } - break; - default: - throw new Exception(JAMAError(PolymorphicArgumentException)); - break; - } - } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); - } - } // function setMatrix() - - /** * checkMatrixDimensions * @@ -412,14 +270,14 @@ class Matrix { * @return boolean */ public function checkMatrixDimensions($B = null) { - if ($B instanceof Matrix) { + if ($B instanceof PHPExcel_Shared_JAMA_Matrix) { if (($this->m == $B->getRowDimension()) && ($this->n == $B->getColumnDimension())) { return true; } else { - throw new Exception(JAMAError(MatrixDimensionException)); + throw new Exception(self::MatrixDimensionException); } } else { - throw new Exception(JAMAError(ArgumentTypeException)); + throw new Exception(self::ArgumentTypeException); } } // function checkMatrixDimensions() @@ -437,18 +295,6 @@ class Matrix { public function set($i = null, $j = null, $c = null) { // Optimized set version just has this $this->A[$i][$j] = $c; - /* - if (is_int($i) && is_int($j) && is_numeric($c)) { - if (($i < $this->m) && ($j < $this->n)) { - $this->A[$i][$j] = $c; - } else { - echo "A[$i][$j] = $c
"; - throw new Exception(JAMAError(ArgumentBoundsException)); - } - } else { - throw new Exception(JAMAError(ArgumentTypeException)); - } - */ } // function set() @@ -475,7 +321,7 @@ class Matrix { * @return Matrix Diagonal matrix */ public function diagonal($m = null, $n = null, $c = 1) { - $R = new Matrix($m, $n); + $R = new PHPExcel_Shared_JAMA_Matrix($m, $n); for($i = 0; $i < $m; ++$i) { $R->set($i, $i, $c); } @@ -483,58 +329,6 @@ class Matrix { } // function diagonal() - /** - * filled - * - * Generate a filled matrix - * @param int $m Row dimension - * @param int $n Column dimension - * @param int $c Fill constant - * @return Matrix Filled matrix - */ - public function filled($m = null, $n = null, $c = 0) { - if (is_int($m) && is_int($n) && is_numeric($c)) { - $R = new Matrix($m, $n, $c); - return $R; - } else { - throw new Exception(JAMAError(ArgumentTypeException)); - } - } // function filled() - - /** - * random - * - * Generate a random matrix - * @param int $m Row dimension - * @param int $n Column dimension - * @return Matrix Random matrix - */ - public function random($m = null, $n = null, $a = RAND_MIN, $b = RAND_MAX) { - if (is_int($m) && is_int($n) && is_numeric($a) && is_numeric($b)) { - $R = new Matrix($m, $n); - for($i = 0; $i < $m; ++$i) { - for($j = 0; $j < $n; ++$j) { - $R->set($i, $j, mt_rand($a, $b)); - } - } - return $R; - } else { - throw new Exception(JAMAError(ArgumentTypeException)); - } - } // function random() - - - /** - * packed - * - * Alias for getRowPacked - * @return array Packed array - */ - public function packed() { - return $this->getRowPacked(); - } // function packed() - - /** * getMatrixByRow * @@ -551,7 +345,7 @@ class Matrix { return $this->getMatrix($i0, 0, $i0 + 1, $this->n); } } else { - throw new Exception(JAMAError(ArgumentTypeException)); + throw new Exception(self::ArgumentTypeException); } } // function getMatrixByRow() @@ -572,7 +366,7 @@ class Matrix { return $this->getMatrix(0, $j0, $this->m, $j0 + 1); } } else { - throw new Exception(JAMAError(ArgumentTypeException)); + throw new Exception(self::ArgumentTypeException); } } // function getMatrixByCol() @@ -584,7 +378,7 @@ class Matrix { * @return Matrix Transposed matrix */ public function transpose() { - $R = new Matrix($this->n, $this->m); + $R = new PHPExcel_Shared_JAMA_Matrix($this->n, $this->m); for($i = 0; $i < $this->m; ++$i) { for($j = 0; $j < $this->n; ++$j) { $R->set($j, $i, $this->A[$i][$j]); @@ -594,93 +388,6 @@ class Matrix { } // function transpose() - /** - * norm1 - * - * One norm - * @return float Maximum column sum - */ - public function norm1() { - $r = 0; - for($j = 0; $j < $this->n; ++$j) { - $s = 0; - for($i = 0; $i < $this->m; ++$i) { - $s += abs($this->A[$i][$j]); - } - $r = ($r > $s) ? $r : $s; - } - return $r; - } // function norm1() - - - /** - * norm2 - * - * Maximum singular value - * @return float Maximum singular value - */ - public function norm2() { - } // function norm2() - - - /** - * normInf - * - * Infinite norm - * @return float Maximum row sum - */ - public function normInf() { - $r = 0; - for($i = 0; $i < $this->m; ++$i) { - $s = 0; - for($j = 0; $j < $this->n; ++$j) { - $s += abs($this->A[$i][$j]); - } - $r = ($r > $s) ? $r : $s; - } - return $r; - } // function normInf() - - - /** - * normF - * - * Frobenius norm - * @return float Square root of the sum of all elements squared - */ - public function normF() { - $f = 0; - for ($i = 0; $i < $this->m; ++$i) { - for ($j = 0; $j < $this->n; ++$j) { - $f = hypo($f,$this->A[$i][$j]); - } - } - return $f; - } // function normF() - - - /** - * Matrix rank - * - * @return effective numerical rank, obtained from SVD. - */ - public function rank () { - $svd = new SingularValueDecomposition($this); - return $svd->rank(); - } // function rank () - - - /** - * Matrix condition (2 norm) - * - * @return ratio of largest to smallest singular value. - */ - public function cond () { - $svd = new SingularValueDecomposition($this); - return $svd->cond(); - } // function cond () - - /** * trace * @@ -721,13 +428,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -738,7 +445,7 @@ class Matrix { } return $M; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function plus() @@ -757,13 +464,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -788,7 +495,7 @@ class Matrix { } return $this; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function plusEquals() @@ -807,13 +514,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -824,7 +531,7 @@ class Matrix { } return $M; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function minus() @@ -843,13 +550,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -874,7 +581,7 @@ class Matrix { } return $this; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function minusEquals() @@ -894,13 +601,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -911,7 +618,7 @@ class Matrix { } return $M; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function arrayTimes() @@ -931,13 +638,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -962,7 +669,7 @@ class Matrix { } return $this; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function arrayTimesEquals() @@ -982,13 +689,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -1012,13 +719,13 @@ class Matrix { $M->set($i, $j, $this->A[$i][$j] / $value); } } else { - $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN(); + $M->set($i, $j, PHPExcel_Calculation_Functions::NaN()); } } } return $M; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function arrayRightDivide() @@ -1038,13 +745,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -1055,7 +762,7 @@ class Matrix { } return $M; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function arrayRightDivideEquals() @@ -1075,13 +782,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -1092,7 +799,7 @@ class Matrix { } return $M; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function arrayLeftDivide() @@ -1112,13 +819,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -1129,7 +836,7 @@ class Matrix { } return $M; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function arrayLeftDivideEquals() @@ -1148,9 +855,9 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $B = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $B = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } if ($this->n == $B->m) { - $C = new Matrix($this->m, $B->n); + $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $B->n); for($j = 0; $j < $B->n; ++$j) { for ($k = 0; $k < $this->n; ++$k) { $Bcolj[$k] = $B->A[$k][$j]; @@ -1170,9 +877,9 @@ class Matrix { } break; case 'array': - $B = new Matrix($args[0]); + $B = new PHPExcel_Shared_JAMA_Matrix($args[0]); if ($this->n == $B->m) { - $C = new Matrix($this->m, $B->n); + $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $B->n); for($i = 0; $i < $C->m; ++$i) { for($j = 0; $j < $C->n; ++$j) { $s = "0"; @@ -1189,7 +896,7 @@ class Matrix { return $M; break; case 'integer': - $C = new Matrix($this->A); + $C = new PHPExcel_Shared_JAMA_Matrix($this->A); for($i = 0; $i < $C->m; ++$i) { for($j = 0; $j < $C->n; ++$j) { $C->A[$i][$j] *= $args[0]; @@ -1198,7 +905,7 @@ class Matrix { return $C; break; case 'double': - $C = new Matrix($this->m, $this->n); + $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $this->n); for($i = 0; $i < $C->m; ++$i) { for($j = 0; $j < $C->n; ++$j) { $C->A[$i][$j] = $args[0] * $this->A[$i][$j]; @@ -1207,7 +914,7 @@ class Matrix { return $C; break; case 'float': - $C = new Matrix($this->A); + $C = new PHPExcel_Shared_JAMA_Matrix($this->A); for($i = 0; $i < $C->m; ++$i) { for($j = 0; $j < $C->n; ++$j) { $C->A[$i][$j] *= $args[0]; @@ -1216,11 +923,11 @@ class Matrix { return $C; break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } } else { - throw new Exception(PolymorphicArgumentException); + throw new Exception(self::PolymorphicArgumentException); } } // function times() @@ -1239,13 +946,13 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } break; case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); @@ -1270,7 +977,7 @@ class Matrix { } return $this; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function power() @@ -1289,83 +996,27 @@ class Matrix { switch($match) { case 'object': - if ($args[0] instanceof Matrix) { $M = $args[0]; } else { throw new Exception(JAMAError(ArgumentTypeException)); } + if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) { $M = $args[0]; } else { throw new Exception(self::ArgumentTypeException); } case 'array': - $M = new Matrix($args[0]); + $M = new PHPExcel_Shared_JAMA_Matrix($args[0]); break; default: - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); break; } $this->checkMatrixDimensions($M); for($i = 0; $i < $this->m; ++$i) { for($j = 0; $j < $this->n; ++$j) { -// $this->A[$i][$j] = '"'.trim($this->A[$i][$j],'"').trim($M->get($i, $j),'"').'"'; $this->A[$i][$j] = trim($this->A[$i][$j],'"').trim($M->get($i, $j),'"'); } } return $this; } else { - throw new Exception(JAMAError(PolymorphicArgumentException)); + throw new Exception(self::PolymorphicArgumentException); } } // function concat() - /** - * chol - * - * Cholesky decomposition - * @return Matrix Cholesky decomposition - */ - public function chol() { - return new CholeskyDecomposition($this); - } // function chol() - - - /** - * lu - * - * LU decomposition - * @return Matrix LU decomposition - */ - public function lu() { - return new LUDecomposition($this); - } // function lu() - - - /** - * qr - * - * QR decomposition - * @return Matrix QR decomposition - */ - public function qr() { - return new QRDecomposition($this); - } // function qr() - - - /** - * eig - * - * Eigenvalue decomposition - * @return Matrix Eigenvalue decomposition - */ - public function eig() { - return new EigenvalueDecomposition($this); - } // function eig() - - - /** - * svd - * - * Singular value decomposition - * @return Singular value decomposition - */ - public function svd() { - return new SingularValueDecomposition($this); - } // function svd() - - /** * Solve A*X = B. * @@ -1374,7 +1025,7 @@ class Matrix { */ public function solve($B) { if ($this->m == $this->n) { - $LU = new LUDecomposition($this); + $LU = new PHPExcel_Shared_JAMA_LUDecomposition($this); return $LU->solve($B); } else { $QR = new QRDecomposition($this); @@ -1400,46 +1051,9 @@ class Matrix { * @return float Determinant */ public function det() { - $L = new LUDecomposition($this); + $L = new PHPExcel_Shared_JAMA_LUDecomposition($this); return $L->det(); } // function det() - /** - * Older debugging utility for backwards compatability. - * - * @return html version of matrix - */ - public function mprint($A, $format="%01.2f", $width=2) { - $m = count($A); - $n = count($A[0]); - $spacing = str_repeat(' ',$width); - - for ($i = 0; $i < $m; ++$i) { - for ($j = 0; $j < $n; ++$j) { - $formatted = sprintf($format, $A[$i][$j]); - echo $formatted.$spacing; - } - echo "
"; - } - } // function mprint() - - - /** - * Debugging utility. - * - * @return Output HTML representation of matrix - */ - public function toHTML($width=2) { - print(''); - for($i = 0; $i < $this->m; ++$i) { - print(''); - for($j = 0; $j < $this->n; ++$j) { - print(''); - } - print(''); - } - print('
' . $this->A[$i][$j] . '
'); - } // function toHTML() - -} // class Matrix +} // class PHPExcel_Shared_JAMA_Matrix diff --git a/libraries/PHPExcel/PHPExcel/Shared/JAMA/QRDecomposition.php b/libraries/PHPExcel/PHPExcel/Shared/JAMA/QRDecomposition.php index 80680594d..49293d7ec 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/JAMA/QRDecomposition.php +++ b/libraries/PHPExcel/PHPExcel/Shared/JAMA/QRDecomposition.php @@ -16,7 +16,9 @@ * @license PHP v3.0 * @version 1.1 */ -class QRDecomposition { +class PHPExcel_Shared_JAMA_QRDecomposition { + + const MatrixRankException = "Can only perform operation on full-rank matrix."; /** * Array for internal storage of decomposition. @@ -50,7 +52,7 @@ class QRDecomposition { * @return Structure to access R and the Householder vectors and compute Q. */ public function __construct($A) { - if($A instanceof Matrix) { + if($A instanceof PHPExcel_Shared_JAMA_Matrix) { // Initialize. $this->QR = $A->getArrayCopy(); $this->m = $A->getRowDimension(); @@ -86,7 +88,7 @@ class QRDecomposition { $this->Rdiag[$k] = -$nrm; } } else { - throw new Exception(JAMAError(ArgumentTypeException)); + throw new Exception(PHPExcel_Shared_JAMA_Matrix::ArgumentTypeException); } } // function __construct() @@ -121,7 +123,7 @@ class QRDecomposition { } } } - return new Matrix($H); + return new PHPExcel_Shared_JAMA_Matrix($H); } // function getH() @@ -142,7 +144,7 @@ class QRDecomposition { } } } - return new Matrix($R); + return new PHPExcel_Shared_JAMA_Matrix($R); } // function getR() @@ -179,7 +181,7 @@ class QRDecomposition { } } */ - return new Matrix($Q); + return new PHPExcel_Shared_JAMA_Matrix($Q); } // function getQ() @@ -219,14 +221,14 @@ class QRDecomposition { } } } - $X = new Matrix($X); + $X = new PHPExcel_Shared_JAMA_Matrix($X); return ($X->getMatrix(0, $this->n-1, 0, $nx)); } else { - throw new Exception(JAMAError(MatrixRankException)); + throw new Exception(self::MatrixRankException); } } else { - throw new Exception(JAMAError(MatrixDimensionException)); + throw new Exception(PHPExcel_Shared_JAMA_Matrix::MatrixDimensionException); } } // function solve() -} // class QRDecomposition +} // PHPExcel_Shared_JAMA_class QRDecomposition diff --git a/libraries/PHPExcel/PHPExcel/Shared/OLE.php b/libraries/PHPExcel/PHPExcel/Shared/OLE.php index a7cc9c3d8..a5c8dd1d0 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/OLE.php +++ b/libraries/PHPExcel/PHPExcel/Shared/OLE.php @@ -111,36 +111,36 @@ class PHPExcel_Shared_OLE throw new Exception("Only Little-Endian encoding is supported."); } // Size of blocks and short blocks in bytes - $this->bigBlockSize = pow(2, $this->_readInt2($fh)); - $this->smallBlockSize = pow(2, $this->_readInt2($fh)); + $this->bigBlockSize = pow(2, self::_readInt2($fh)); + $this->smallBlockSize = pow(2, self::_readInt2($fh)); // Skip UID, revision number and version number fseek($fh, 44); // Number of blocks in Big Block Allocation Table - $bbatBlockCount = $this->_readInt4($fh); + $bbatBlockCount = self::_readInt4($fh); // Root chain 1st block - $directoryFirstBlockId = $this->_readInt4($fh); + $directoryFirstBlockId = self::_readInt4($fh); // Skip unused bytes fseek($fh, 56); // Streams shorter than this are stored using small blocks - $this->bigBlockThreshold = $this->_readInt4($fh); + $this->bigBlockThreshold = self::_readInt4($fh); // Block id of first sector in Short Block Allocation Table - $sbatFirstBlockId = $this->_readInt4($fh); + $sbatFirstBlockId = self::_readInt4($fh); // Number of blocks in Short Block Allocation Table - $sbbatBlockCount = $this->_readInt4($fh); + $sbbatBlockCount = self::_readInt4($fh); // Block id of first sector in Master Block Allocation Table - $mbatFirstBlockId = $this->_readInt4($fh); + $mbatFirstBlockId = self::_readInt4($fh); // Number of blocks in Master Block Allocation Table - $mbbatBlockCount = $this->_readInt4($fh); + $mbbatBlockCount = self::_readInt4($fh); $this->bbat = array(); // Remaining 4 * 109 bytes of current block is beginning of Master // Block Allocation Table $mbatBlocks = array(); for ($i = 0; $i < 109; ++$i) { - $mbatBlocks[] = $this->_readInt4($fh); + $mbatBlocks[] = self::_readInt4($fh); } // Read rest of Master Block Allocation Table (if any is left) @@ -148,10 +148,10 @@ class PHPExcel_Shared_OLE for ($i = 0; $i < $mbbatBlockCount; ++$i) { fseek($fh, $pos); for ($j = 0; $j < $this->bigBlockSize / 4 - 1; ++$j) { - $mbatBlocks[] = $this->_readInt4($fh); + $mbatBlocks[] = self::_readInt4($fh); } // Last block id in each block points to next block - $pos = $this->_getBlockOffset($this->_readInt4($fh)); + $pos = $this->_getBlockOffset(self::_readInt4($fh)); } // Read Big Block Allocation Table according to chain specified by @@ -160,7 +160,7 @@ class PHPExcel_Shared_OLE $pos = $this->_getBlockOffset($mbatBlocks[$i]); fseek($fh, $pos); for ($j = 0 ; $j < $this->bigBlockSize / 4; ++$j) { - $this->bbat[] = $this->_readInt4($fh); + $this->bbat[] = self::_readInt4($fh); } } @@ -169,7 +169,7 @@ class PHPExcel_Shared_OLE $shortBlockCount = $sbbatBlockCount * $this->bigBlockSize / 4; $sbatFh = $this->getStream($sbatFirstBlockId); for ($blockId = 0; $blockId < $shortBlockCount; ++$blockId) { - $this->sbat[$blockId] = $this->_readInt4($sbatFh); + $this->sbat[$blockId] = self::_readInt4($sbatFh); } fclose($sbatFh); @@ -225,7 +225,7 @@ class PHPExcel_Shared_OLE * @return int * @access public */ - public function _readInt1($fh) + private static function _readInt1($fh) { list(, $tmp) = unpack("c", fread($fh, 1)); return $tmp; @@ -237,7 +237,7 @@ class PHPExcel_Shared_OLE * @return int * @access public */ - public function _readInt2($fh) + private static function _readInt2($fh) { list(, $tmp) = unpack("v", fread($fh, 2)); return $tmp; @@ -249,7 +249,7 @@ class PHPExcel_Shared_OLE * @return int * @access public */ - public function _readInt4($fh) + private static function _readInt4($fh) { list(, $tmp) = unpack("V", fread($fh, 4)); return $tmp; @@ -269,11 +269,11 @@ class PHPExcel_Shared_OLE for ($pos = 0; ; $pos += 128) { fseek($fh, $pos, SEEK_SET); $nameUtf16 = fread($fh, 64); - $nameLength = $this->_readInt2($fh); + $nameLength = self::_readInt2($fh); $nameUtf16 = substr($nameUtf16, 0, $nameLength - 2); // Simple conversion from UTF-16LE to ISO-8859-1 $name = str_replace("\x00", "", $nameUtf16); - $type = $this->_readInt1($fh); + $type = self::_readInt1($fh); switch ($type) { case self::OLE_PPS_TYPE_ROOT: $pps = new PHPExcel_Shared_OLE_PPS_Root(null, null, array()); @@ -292,14 +292,14 @@ class PHPExcel_Shared_OLE fseek($fh, 1, SEEK_CUR); $pps->Type = $type; $pps->Name = $name; - $pps->PrevPps = $this->_readInt4($fh); - $pps->NextPps = $this->_readInt4($fh); - $pps->DirPps = $this->_readInt4($fh); + $pps->PrevPps = self::_readInt4($fh); + $pps->NextPps = self::_readInt4($fh); + $pps->DirPps = self::_readInt4($fh); fseek($fh, 20, SEEK_CUR); $pps->Time1st = self::OLE2LocalDate(fread($fh, 8)); $pps->Time2nd = self::OLE2LocalDate(fread($fh, 8)); - $pps->_StartBlock = $this->_readInt4($fh); - $pps->Size = $this->_readInt4($fh); + $pps->_StartBlock = self::_readInt4($fh); + $pps->Size = self::_readInt4($fh); $pps->No = count($this->_list); $this->_list[] = $pps; diff --git a/libraries/PHPExcel/PHPExcel/Shared/OLE/ChainedBlockStream.php b/libraries/PHPExcel/PHPExcel/Shared/OLE/ChainedBlockStream.php index af757d007..b838b96c2 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/OLE/ChainedBlockStream.php +++ b/libraries/PHPExcel/PHPExcel/Shared/OLE/ChainedBlockStream.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (C) 2006 - 2010 PHPExcel + * Copyright (C) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,7 @@ * @package PHPExcel_Shared_OLE * @copyright Copyright (c) 2006 - 2007 Christian Schmidt * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ /** diff --git a/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS.php b/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS.php index aa1a4265c..e3d4673ab 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS.php +++ b/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS.php @@ -169,10 +169,8 @@ class PHPExcel_Shared_OLE_PPS */ public function _getPpsWk() { - $ret = $this->Name; - for ($i = 0; $i < (64 - strlen($this->Name)); ++$i) { - $ret .= "\x00"; - } + $ret = str_pad($this->Name,64,"\x00"); + $ret .= pack("v", strlen($this->Name) + 2) // 66 . pack("c", $this->Type) // 67 . pack("c", 0x00) //UK // 68 @@ -215,4 +213,4 @@ class PHPExcel_Shared_OLE_PPS } return $this->No; } - } +} diff --git a/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS/Root.php b/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS/Root.php index 412f99282..e73685150 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS/Root.php +++ b/libraries/PHPExcel/PHPExcel/Shared/OLE/PPS/Root.php @@ -29,12 +29,21 @@ */ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS { + + /** + * Directory for temporary files + * @var string + */ + protected $_tmp_dir = ''; + /** * @param integer $time_1st A timestamp * @param integer $time_2nd A timestamp */ public function __construct($time_1st, $time_2nd, $raChild) { + $this->_tempDir = PHPExcel_Shared_File::sys_get_temp_dir(); + parent::__construct( null, PHPExcel_Shared_OLE::Asc2Ucs('Root Entry'), @@ -63,9 +72,9 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS { // Initial Setting for saving $this->_BIG_BLOCK_SIZE = pow(2, - ((isset($this->_BIG_BLOCK_SIZE))? $this->_adjust2($this->_BIG_BLOCK_SIZE) : 9)); + ((isset($this->_BIG_BLOCK_SIZE))? self::_adjust2($this->_BIG_BLOCK_SIZE) : 9)); $this->_SMALL_BLOCK_SIZE= pow(2, - ((isset($this->_SMALL_BLOCK_SIZE))? $this->_adjust2($this->_SMALL_BLOCK_SIZE): 6)); + ((isset($this->_SMALL_BLOCK_SIZE))? self::_adjust2($this->_SMALL_BLOCK_SIZE): 6)); if (is_resource($filename)) { $this->_FILEH_ = $filename; @@ -119,7 +128,8 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0); $iSmallLen = 0; $iSBcnt = 0; - for ($i = 0; $i < count($raList); ++$i) { + $iCount = count($raList); + for ($i = 0; $i < $iCount; ++$i) { if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) { $raList[$i]->Size = $raList[$i]->_DataLen(); if ($raList[$i]->Size < PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) { @@ -151,7 +161,7 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS * @see save() * @return integer */ - public function _adjust2($i2) + private static function _adjust2($i2) { $iWk = log($i2)/log(2); return ($iWk > floor($iWk))? floor($iWk)+1:$iWk; @@ -229,7 +239,8 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS fwrite($FILE, pack("V", $iAll+$i)); } if ($i < $i1stBdL) { - for ($j = 0; $j < ($i1stBdL-$i); ++$j) { + $jB = $i1stBdL - $i; + for ($j = 0; $j < $jB; ++$j) { fwrite($FILE, (pack("V", -1))); } } @@ -247,7 +258,8 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS $FILE = $this->_FILEH_; // cycle through PPS's - for ($i = 0; $i < count($raList); ++$i) { + $iCount = count($raList); + for ($i = 0; $i < $iCount; ++$i) { if ($raList[$i]->Type != PHPExcel_Shared_OLE::OLE_PPS_TYPE_DIR) { $raList[$i]->Size = $raList[$i]->_DataLen(); if (($raList[$i]->Size >= PHPExcel_Shared_OLE::OLE_DATA_SIZE_SMALL) || @@ -266,9 +278,7 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS //} if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE) { - for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)); ++$j) { - fwrite($FILE, "\x00"); - } + fwrite($FILE, str_repeat("\x00", $this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE))); } // Set For PPS $raList[$i]->_StartBlock = $iStBlk; @@ -298,7 +308,8 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS $FILE = $this->_FILEH_; $iSmBlk = 0; - for ($i = 0; $i < count($raList); ++$i) { + $iCount = count($raList); + for ($i = 0; $i < $iCount; ++$i) { // Make SBD, small data string if ($raList[$i]->Type == PHPExcel_Shared_OLE::OLE_PPS_TYPE_FILE) { if ($raList[$i]->Size <= 0) { @@ -308,7 +319,8 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE) + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0); // Add to SBD - for ($j = 0; $j < ($iSmbCnt-1); ++$j) { + $jB = $iSmbCnt - 1; + for ($j = 0; $j < $jB; ++$j) { fwrite($FILE, pack("V", $j+$iSmBlk+1)); } fwrite($FILE, pack("V", -2)); @@ -323,9 +335,7 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS $sRes .= $raList[$i]->_data; //} if ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE) { - for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); ++$j) { - $sRes .= "\x00"; - } + $sRes .= str_repeat("\x00",$this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); } // Set for PPS $raList[$i]->_StartBlock = $iSmBlk; @@ -335,7 +345,8 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS } $iSbCnt = floor($this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_LONG_INT_SIZE); if ($iSmBlk % $iSbCnt) { - for ($i = 0; $i < ($iSbCnt - ($iSmBlk % $iSbCnt)); ++$i) { + $iB = $iSbCnt - ($iSmBlk % $iSbCnt); + for ($i = 0; $i < $iB; ++$i) { fwrite($FILE, pack("V", -1)); } } @@ -351,16 +362,15 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS public function _savePps(&$raList) { // Save each PPS WK - for ($i = 0; $i < count($raList); ++$i) { + $iC = count($raList); + for ($i = 0; $i < $iC; ++$i) { fwrite($this->_FILEH_, $raList[$i]->_getPpsWk()); } // Adjust for Block $iCnt = count($raList); $iBCnt = $this->_BIG_BLOCK_SIZE / PHPExcel_Shared_OLE::OLE_PPS_SIZE; if ($iCnt % $iBCnt) { - for ($i = 0; $i < (($iBCnt - ($iCnt % $iBCnt)) * PHPExcel_Shared_OLE::OLE_PPS_SIZE); ++$i) { - fwrite($this->_FILEH_, "\x00"); - } + fwrite($this->_FILEH_, str_repeat("\x00",($iBCnt - ($iCnt % $iBCnt)) * PHPExcel_Shared_OLE::OLE_PPS_SIZE)); } } @@ -426,7 +436,8 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS } // Adjust for Block if (($iAllW + $iBdCnt) % $iBbCnt) { - for ($i = 0; $i < ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); ++$i) { + $iBlock = ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); + for ($i = 0; $i < $iBlock; ++$i) { fwrite($FILE, pack("V", -1)); } } @@ -443,11 +454,12 @@ class PHPExcel_Shared_OLE_PPS_Root extends PHPExcel_Shared_OLE_PPS fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i)); } if (($iBdCnt-$i1stBdL) % ($iBbCnt-1)) { - for ($i = 0; $i < (($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1))); ++$i) { + $iB = ($iBbCnt - 1) - (($iBdCnt - $i1stBdL) % ($iBbCnt - 1)); + for ($i = 0; $i < $iB; ++$i) { fwrite($FILE, pack("V", -1)); } } fwrite($FILE, pack("V", -2)); } } - } +} diff --git a/libraries/PHPExcel/PHPExcel/Shared/OLERead.php b/libraries/PHPExcel/PHPExcel/Shared/OLERead.php index 6aebbf017..d6a58d6bc 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/OLERead.php +++ b/libraries/PHPExcel/PHPExcel/Shared/OLERead.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ define('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1)); @@ -59,6 +59,13 @@ class PHPExcel_Shared_OLERead { const START_BLOCK_POS = 0x74; const SIZE_POS = 0x78; + + + public $wrkbook = null; + public $summaryInformation = null; + public $documentSummaryInformation = null; + + /** * Read the file * @@ -81,19 +88,19 @@ class PHPExcel_Shared_OLERead { } // Total number of sectors used for the SAT - $this->numBigBlockDepotBlocks = $this->_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS); + $this->numBigBlockDepotBlocks = self::_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS); // SecID of the first sector of the directory stream - $this->rootStartBlock = $this->_GetInt4d($this->data, self::ROOT_START_BLOCK_POS); + $this->rootStartBlock = self::_GetInt4d($this->data, self::ROOT_START_BLOCK_POS); // SecID of the first sector of the SSAT (or -2 if not extant) - $this->sbdStartBlock = $this->_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS); + $this->sbdStartBlock = self::_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS); // SecID of the first sector of the MSAT (or -2 if no additional sectors are used) - $this->extensionBlock = $this->_GetInt4d($this->data, self::EXTENSION_BLOCK_POS); + $this->extensionBlock = self::_GetInt4d($this->data, self::EXTENSION_BLOCK_POS); // Total number of sectors used by MSAT - $this->numExtensionBlocks = $this->_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS); + $this->numExtensionBlocks = self::_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS); $bigBlockDepotBlocks = array(); $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS; @@ -105,7 +112,7 @@ class PHPExcel_Shared_OLERead { } for ($i = 0; $i < $bbdBlocks; ++$i) { - $bigBlockDepotBlocks[$i] = $this->_GetInt4d($this->data, $pos); + $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos); $pos += 4; } @@ -114,40 +121,39 @@ class PHPExcel_Shared_OLERead { $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1); for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) { - $bigBlockDepotBlocks[$i] = $this->_GetInt4d($this->data, $pos); + $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos); $pos += 4; } $bbdBlocks += $blocksToRead; if ($bbdBlocks < $this->numBigBlockDepotBlocks) { - $this->extensionBlock = $this->_GetInt4d($this->data, $pos); + $this->extensionBlock = self::_GetInt4d($this->data, $pos); } } - $pos = 0; - $index = 0; + $pos = $index = 0; $this->bigBlockChain = array(); + $bbs = self::BIG_BLOCK_SIZE / 4; for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) { $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE; - for ($j = 0 ; $j < self::BIG_BLOCK_SIZE / 4; ++$j) { - $this->bigBlockChain[$index] = $this->_GetInt4d($this->data, $pos); + for ($j = 0 ; $j < $bbs; ++$j) { + $this->bigBlockChain[$index] = self::_GetInt4d($this->data, $pos); $pos += 4 ; ++$index; } } - $pos = 0; - $index = 0; + $pos = $index = 0; $sbdBlock = $this->sbdStartBlock; $this->smallBlockChain = array(); while ($sbdBlock != -2) { $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE; - for ($j = 0; $j < self::BIG_BLOCK_SIZE / 4; ++$j) { - $this->smallBlockChain[$index] = $this->_GetInt4d($this->data, $pos); + for ($j = 0; $j < $bbs; ++$j) { + $this->smallBlockChain[$index] = self::_GetInt4d($this->data, $pos); $pos += 4; ++$index; } @@ -155,81 +161,31 @@ class PHPExcel_Shared_OLERead { $sbdBlock = $this->bigBlockChain[$sbdBlock]; } - $block = $this->rootStartBlock; - $pos = 0; - // read the directory stream + $block = $this->rootStartBlock; $this->entry = $this->_readData($block); $this->_readPropertySets(); } /** - * Extract binary stream data, workbook stream + sheet streams + * Extract binary stream data * * @return string */ - public function getWorkBook() + public function getStream($stream) { - if ($this->props[$this->wrkbook]['size'] < self::SMALL_BLOCK_THRESHOLD){ - $rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']); - - $streamData = ''; - $block = $this->props[$this->wrkbook]['startBlock']; - - $pos = 0; - while ($block != -2) { - $pos = $block * self::SMALL_BLOCK_SIZE; - $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE); - - $block = $this->smallBlockChain[$block]; - } - - return $streamData; - - - } else { - $numBlocks = $this->props[$this->wrkbook]['size'] / self::BIG_BLOCK_SIZE; - if ($this->props[$this->wrkbook]['size'] % self::BIG_BLOCK_SIZE != 0) { - ++$numBlocks; - } - - if ($numBlocks == 0) return ''; - - - $streamData = ''; - $block = $this->props[$this->wrkbook]['startBlock']; - - $pos = 0; - - while ($block != -2) { - $pos = ($block + 1) * self::BIG_BLOCK_SIZE; - $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE); - $block = $this->bigBlockChain[$block]; - } - - return $streamData; - } - } - - /** - * Extract binary stream data, summary information - * - * @return string|null - */ - public function getSummaryInformation() - { - if (!isset($this->summaryInformation)) { + if (is_null($stream)) { return null; } - if ($this->props[$this->summaryInformation]['size'] < self::SMALL_BLOCK_THRESHOLD){ + $streamData = ''; + + if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) { $rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']); - $streamData = ''; - $block = $this->props[$this->summaryInformation]['startBlock']; + $block = $this->props[$stream]['startBlock']; - $pos = 0; while ($block != -2) { $pos = $block * self::SMALL_BLOCK_SIZE; $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE); @@ -238,21 +194,15 @@ class PHPExcel_Shared_OLERead { } return $streamData; - - } else { - $numBlocks = $this->props[$this->summaryInformation]['size'] / self::BIG_BLOCK_SIZE; - if ($this->props[$this->summaryInformation]['size'] % self::BIG_BLOCK_SIZE != 0) { + $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE; + if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) { ++$numBlocks; } if ($numBlocks == 0) return ''; - - $streamData = ''; - $block = $this->props[$this->summaryInformation]['startBlock']; - - $pos = 0; + $block = $this->props[$stream]['startBlock']; while ($block != -2) { $pos = ($block + 1) * self::BIG_BLOCK_SIZE; @@ -273,12 +223,11 @@ class PHPExcel_Shared_OLERead { private function _readData($bl) { $block = $bl; - $pos = 0; $data = ''; while ($block != -2) { $pos = ($block + 1) * self::BIG_BLOCK_SIZE; - $data = $data . substr($this->data, $pos, self::BIG_BLOCK_SIZE); + $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE); $block = $this->bigBlockChain[$block]; } return $data; @@ -287,12 +236,12 @@ class PHPExcel_Shared_OLERead { /** * Read entries in the directory stream. */ - private function _readPropertySets() - { + private function _readPropertySets() { $offset = 0; // loop through entires, each entry is 128 bytes - while ($offset < strlen($this->entry)) { + $entryLen = strlen($this->entry); + while ($offset < $entryLen) { // entry data (128 bytes) $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE); @@ -304,16 +253,11 @@ class PHPExcel_Shared_OLERead { // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook) // sectorID of first sector of the short-stream container stream, if this entry is root entry - $startBlock = $this->_GetInt4d($d, self::START_BLOCK_POS); + $startBlock = self::_GetInt4d($d, self::START_BLOCK_POS); - $size = $this->_GetInt4d($d, self::SIZE_POS); + $size = self::_GetInt4d($d, self::SIZE_POS); - $name = ''; - for ($i = 0; $i < $nameSize ; ++$i) { - $name .= $d[$i]; - } - - $name = str_replace("\x00", "", $name); + $name = str_replace("\x00", "", substr($d,0,$nameSize)); $this->props[] = array ( 'name' => $name, @@ -333,9 +277,16 @@ class PHPExcel_Shared_OLERead { // Summary information if ($name == chr(5) . 'SummaryInformation') { +// echo 'Summary Information
'; $this->summaryInformation = count($this->props) - 1; } + // Additional Document Summary information + if ($name == chr(5) . 'DocumentSummaryInformation') { +// echo 'Document Summary Information
'; + $this->documentSummaryInformation = count($this->props) - 1; + } + $offset += self::PROPERTY_STORAGE_BLOCK_SIZE; } @@ -348,14 +299,19 @@ class PHPExcel_Shared_OLERead { * @param int $pos * @return int */ - private function _GetInt4d($data, $pos) + private static function _GetInt4d($data, $pos) { + // FIX: represent numbers correctly on 64-bit system + // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334 // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems - $_or_24 = ord($data[$pos+3]); - if ($_or_24>=128) $_ord_24 = -abs((256-$_or_24) << 24); - else $_ord_24 = ($_or_24&127) << 24; - - return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $_ord_24; + $_or_24 = ord($data[$pos + 3]); + if ($_or_24 >= 128) { + // negative number + $_ord_24 = -abs((256 - $_or_24) << 24); + } else { + $_ord_24 = ($_or_24 & 127) << 24; + } + return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24; } } diff --git a/libraries/PHPExcel/PHPExcel/Shared/PCLZip/gnu-lgpl.txt b/libraries/PHPExcel/PHPExcel/Shared/PCLZip/gnu-lgpl.txt new file mode 100644 index 000000000..cbee875ba --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Shared/PCLZip/gnu-lgpl.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/libraries/PHPExcel/PHPExcel/Shared/PCLZip/pclzip.lib.php b/libraries/PHPExcel/PHPExcel/Shared/PCLZip/pclzip.lib.php new file mode 100644 index 000000000..4bf05a523 --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Shared/PCLZip/pclzip.lib.php @@ -0,0 +1,5694 @@ +zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; + + // ----- Return + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function create($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove from the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Invalid number / type of arguments"); + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + if ($v_string != '') { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + else { + } + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function add($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exist and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + function listContent() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) + { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function extract() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Trace + + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, + $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extractByIndex($p_index, options...) + function extractByIndex($p_index) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + } + else { + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Trace + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, + array (PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function delete() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); + return(0); + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + function deleteByIndex($p_index) + { + + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + function properties() + { + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); + return(0); + } + + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; + + // ----- Look if file exists + if (@is_file($this->zipname)) + { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return 0; + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + function duplicate($p_archive) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) + { + + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); + } + + // ----- Look if the $p_archive is a string (so a filename) + else if (is_string($p_archive)) + { + + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } + else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + function merge($p_archive_to_add) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) + { + + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); + } + + // ----- Look if the $p_archive_to_add is a string (so a filename) + else if (is_string($p_archive_to_add)) + { + + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); + + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorCode() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorCode()); + } + else { + return($this->error_code); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorName($p_with_code=false) + { + $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' + ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' + ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' + ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } + else { + $v_value = 'NoName'; + } + + if ($p_with_code) { + return($v_value.' ('.$this->error_code.')'); + } + else { + return($v_value); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorInfo($p_full=false) + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorString()); + } + else { + if ($p_full) { + return($this->errorName(true)." : ".$this->error_string); + } + else { + return($this->error_string." [code ".$this->error_code."]"); + } + } + } + // -------------------------------------------------------------------------------- + + +// -------------------------------------------------------------------------------- +// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** +// ***** ***** +// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** +// -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + function privCheckFormat($p_level=0) + { + $v_result = true; + + // ----- Reset the file system cache + clearstatcache(); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); + return(false); + } + + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); + return(false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) + { + $v_result=1; + + // ----- Read the options + $i=0; + while ($i<$p_size) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH : + case PCLZIP_OPT_REMOVE_PATH : + case PCLZIP_OPT_ADD_PATH : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_THRESHOLD : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + // ----- Check the value + $v_value = $p_options_list[$i+1]; + if ((!is_integer($v_value)) || ($v_value<0)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Get the value (and convert it in bytes) + $v_result_list[$p_options_list[$i]] = $v_value*1048576; + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_ON : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_TEMP_FILE_OFF : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); + return PclZip::errorCode(); + } + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if ( is_string($p_options_list[$i+1]) + && ($p_options_list[$i+1] != '')) { + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + } + else { + } + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG : + // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG + // to PCLZIP_OPT_BY_PREG + $p_options_list[$i] = PCLZIP_OPT_BY_PREG; + case PCLZIP_OPT_BY_PREG : + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT : + case PCLZIP_OPT_ADD_COMMENT : + case PCLZIP_OPT_PREPEND_COMMENT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, + "Missing parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, + "Wrong parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i+1])) { + + // ----- Remove spaces + $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i+1]); + } + else if (is_integer($p_options_list[$i+1])) { + $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_work_list = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag=false; + $v_sort_value=0; + for ($j=0; $j= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT : + case PCLZIP_CB_POST_EXTRACT : + case PCLZIP_CB_PRE_ADD : + case PCLZIP_CB_POST_ADD : + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i+1]; + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '" + .$p_options_list[$i]."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Next options + $i++; + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + + // ----- Return + return PclZip::errorCode(); + } + } + } + } + + // ----- Look for default values + if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOptionDefaultThreshold() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privOptionDefaultThreshold(&$p_options) + { + $v_result=1; + + if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { + return $v_result; + } + + // ----- Get 'memory_limit' configuration value + $v_memory_limit = ini_get('memory_limit'); + $v_memory_limit = trim($v_memory_limit); + $last = strtolower(substr($v_memory_limit, -1)); + + if($last == 'g') + //$v_memory_limit = $v_memory_limit*1024*1024*1024; + $v_memory_limit = $v_memory_limit*1073741824; + if($last == 'm') + //$v_memory_limit = $v_memory_limit*1024*1024; + $v_memory_limit = $v_memory_limit*1048576; + if($last == 'k') + $v_memory_limit = $v_memory_limit*1024; + + $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); + + + // ----- Sanity check : No threshold if value lower than 1M + if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { + unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrParseAtt() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) + { + $v_result=1; + + // ----- For each file in the list check the attributes + foreach ($p_file_list as $v_key => $v_value) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$v_key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for attribute + switch ($v_key) { + case PCLZIP_ATT_FILE_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + break; + + case PCLZIP_ATT_FILE_NEW_SHORT_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + case PCLZIP_ATT_FILE_NEW_FULL_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + // ----- Look for options that takes a string + case PCLZIP_ATT_FILE_COMMENT : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + break; + + case PCLZIP_ATT_FILE_MTIME : + if (!is_integer($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + break; + + case PCLZIP_ATT_FILE_CONTENT : + $p_filedescr['content'] = $v_value; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '".$v_key."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // This method look for each item of the list to see if its a file, a folder + // or a string to be added as file. For any other type of files (link, other) + // just ignore the item. + // Then prepare the information that will be stored for that file. + // When its a folder, expand the folder with all the files that are in that + // folder (recursively). + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + $v_result=1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + + // ----- Skip '.' and '..' + if (($v_item_handler == '.') || ($v_item_handler == '..')) { + continue; + } + + // ----- Compose the full filename + $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; + + // ----- Look for different stored filename + // Because the name of the folder was changed, the name of the + // files/sub-folders also change + if (($v_descr['stored_filename'] != $v_descr['filename']) + && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + if ($v_descr['stored_filename'] != '') { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; + } + else { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; + } + } + + $v_dirlist_nb++; + } + + @closedir($v_folder_handler); + } + else { + // TBC : unable to open folder in read mode + } + + // ----- Expand each element of the list + if ($v_dirlist_nb != 0) { + // ----- Expand + if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { + return $v_result; + } + + // ----- Concat the resulting list + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + } + else { + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) + { + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + + // ----- Return + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Create the Central Dir files header + for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privOpenFd($p_mode) + { + $v_result=1; + + // ----- Look if already open + if ($this->zip_fd != 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privCloseFd() + { + $v_result=1; + + if ($this->zip_fd != 0) + @fclose($this->zip_fd); + $this->zip_fd = 0; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- +// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + function privAddList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Create the Central Dir files header + for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // Parameters : + // $p_filedescr_list : An array containing the file description + // or directory names to add in the zip + // $p_result_list : list of added files with their properties (specially the status field) + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + + // ----- Loop on the files + for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header, + $p_options); + if ($v_result != 1) { + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=1; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // TBC : Already done in the fileAtt check ... ? + if ($p_filename == "") { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + } + else { + $v_stored_filename = $p_filedescr['stored_filename']; + } + */ + + // ----- Set the file properties + clearstatcache(); + $p_header['version'] = 20; + $p_header['version_extracted'] = 10; + $p_header['flag'] = 0; + $p_header['compression'] = 0; + $p_header['crc'] = 0; + $p_header['compressed_size'] = 0; + $p_header['filename_len'] = strlen($p_filename); + $p_header['extra_len'] = 0; + $p_header['disk'] = 0; + $p_header['internal'] = 0; + $p_header['offset'] = 0; + $p_header['filename'] = $p_filename; +// TBC : Removed $p_header['stored_filename'] = $v_stored_filename; + $p_header['stored_filename'] = $p_filedescr['stored_filename']; + $p_header['extra'] = ''; + $p_header['status'] = 'ok'; + $p_header['index'] = -1; + + // ----- Look for regular file + if ($p_filedescr['type']=='file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for regular folder + else if ($p_filedescr['type']=='folder') { + $p_header['external'] = 0x00000010; + $p_header['mtime'] = filemtime($p_filename); + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for virtual file + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = strlen($p_filedescr['content']); + } + + + // ----- Look for filetime + if (isset($p_filedescr['mtime'])) { + $p_header['mtime'] = $p_filedescr['mtime']; + } + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['mtime'] = time(); + } + else { + $p_header['mtime'] = filemtime($p_filename); + } + + // ------ Look for file comment + if (isset($p_filedescr['comment'])) { + $p_header['comment_len'] = strlen($p_filedescr['comment']); + $p_header['comment'] = $p_filedescr['comment']; + } + else { + $p_header['comment_len'] = 0; + $p_header['comment'] = ''; + } + + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); + } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { + + // ----- Look for a file + if ($p_filedescr['type'] == 'file') { + // ----- Look for using temporary file to zip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { + $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Use "in memory" zip algo + else { + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + } + + } + + // ----- Look for a virtual file (a file from string) + else if ($p_filedescr['type'] == 'virtual_file') { + + $v_content = $p_filedescr['content']; + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + } + + // ----- Look for a directory + else if ($p_filedescr['type'] == 'folder') { + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) + { + return $v_result; + } + } + } + + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=PCLZIP_ERR_NO_ERROR; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Creates a compressed temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = filesize($p_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @gzputs($v_file_compressed, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file); + @gzclose($v_file_compressed); + + // ----- Check the minimum file size + if (filesize($v_gzip_temp_name) < 18) { + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); + return PclZip::errorCode(); + } + + // ----- Extract the compressed attributes + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the gzip file header + $v_binary_data = @fread($v_file_compressed, 10); + $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); + + // ----- Check some parameters + $v_data_header['os'] = bin2hex($v_data_header['os']); + + // ----- Read the gzip file footer + @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); + $v_binary_data = @fread($v_file_compressed, 8); + $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); + + // ----- Set the attributes + $p_header['compression'] = ord($v_data_header['cm']); + //$p_header['mtime'] = $v_data_header['mtime']; + $p_header['crc'] = $v_data_footer['crc']; + $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } + + // ----- Add the compressed data + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) + { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + fseek($v_file_compressed, 10); + $v_size = $p_header['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file_compressed, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Unlink the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCalculateStoredFilename() + // Description : + // Based on file descriptor properties and global options, this method + // calculate the filename that will be stored in the archive. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCalculateStoredFilename(&$p_filedescr, &$p_options) + { + $v_result=1; + + // ----- Working variables + $p_filename = $p_filedescr['filename']; + if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { + $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; + } + else { + $p_add_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { + $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; + } + else { + $p_remove_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + else { + $p_remove_all_dir = 0; + } + + + // ----- Look for full name change + if (isset($p_filedescr['new_full_name'])) { + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); + } + + // ----- Look for path and/or short name change + else { + + // ----- Look for short name change + // Its when we cahnge just the filename but not the path + if (isset($p_filedescr['new_short_name'])) { + $v_path_info = pathinfo($p_filename); + $v_dir = ''; + if ($v_path_info['dirname'] != '') { + $v_dir = $v_path_info['dirname'].'/'; + } + $v_stored_filename = $v_dir.$p_filedescr['new_short_name']; + } + else { + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + } + + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + } + // ----- Look for partial path remove + else if ($p_remove_dir != "") { + if (substr($p_remove_dir, -1) != '/') + $p_remove_dir .= "/"; + + if ( (substr($p_filename, 0, 2) == "./") + || (substr($p_remove_dir, 0, 2) == "./")) { + + if ( (substr($p_filename, 0, 2) == "./") + && (substr($p_remove_dir, 0, 2) != "./")) { + $p_remove_dir = "./".$p_remove_dir; + } + if ( (substr($p_filename, 0, 2) != "./") + && (substr($p_remove_dir, 0, 2) == "./")) { + $p_remove_dir = substr($p_remove_dir, 2); + } + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, + $v_stored_filename); + if ($v_compare > 0) { + if ($v_compare == 2) { + $v_stored_filename = ""; + } + else { + $v_stored_filename = substr($v_stored_filename, + strlen($p_remove_dir)); + } + } + } + + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); + + // ----- Look for path to add + if ($p_add_dir != "") { + if (substr($p_add_dir, -1) == "/") + $v_stored_filename = $p_add_dir.$v_stored_filename; + else + $v_stored_filename = $p_add_dir."/".$v_stored_filename; + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteFileHeader(&$p_header) + { + $v_result=1; + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, + $p_header['version_extracted'], $p_header['flag'], + $p_header['compression'], $v_mtime, $v_mdate, + $p_header['crc'], $p_header['compressed_size'], + $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len']); + + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralFileHeader(&$p_header) + { + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, + $p_header['version'], $p_header['version_extracted'], + $p_header['flag'], $p_header['compression'], + $v_mtime, $v_mdate, $p_header['crc'], + $p_header['compressed_size'], $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len'], $p_header['comment_len'], + $p_header['disk'], $p_header['internal'], + $p_header['external'], $p_header['offset']); + + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) + { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + $v_result=1; + + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, + $p_nb_entries, $p_size, + $p_offset, strlen($p_comment)); + + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); + + // ----- Write the variable fields + if (strlen($p_comment) != 0) + { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privList() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privList(&$p_list) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of Central Dir + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + for ($i=0; $i<$v_central_dir['entries']; $i++) + { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + $v_header['index'] = $i; + + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // $p_info['crc'] = CRC of the file content. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privConvertHeader2FileInfo($p_header, &$p_info) + { + $v_result=1; + + // ----- Get the interesting attributes + $v_temp_path = PclZipUtilPathReduction($p_header['filename']); + $p_info['filename'] = $v_temp_path; + $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); + $p_info['stored_filename'] = $v_temp_path; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + $p_info['crc'] = $p_header['crc']; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check the path + if ( ($p_path == "") + || ( (substr($p_path, 0, 1) != "/") + && (substr($p_path, 0, 3) != "../") + && (substr($p_path,1,2)!=":/"))) + $p_path = "./".$p_path; + + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) + { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") + { + $p_path = substr($p_path, 0, strlen($p_path)-1); + } + } + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) + { + $p_remove_path .= '/'; + } + $p_remove_path_size = strlen($p_remove_path); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + + // ----- Read each entry + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read next Central dir entry + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Store the index + $v_header['index'] = $i; + + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); + + // ----- Look for the specific extract rules + $v_extract = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_extract = true; + } + } + // ----- Look for a filename + elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_extract = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + + // ----- Look for no rule, which means extract all the archive + else { + $v_extract = true; + } + + // ----- Check compression method + if ( ($v_extract) + && ( ($v_header['compression'] != 8) + && ($v_header['compression'] != 0))) { + $v_header['status'] = 'unsupported_compression'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, + "Filename '".$v_header['stored_filename']."' is " + ."compressed by an unsupported compression " + ."method (".$v_header['compression'].") "); + + return PclZip::errorCode(); + } + } + + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + $v_header['status'] = 'unsupported_encryption'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, + "Unsupported encryption for " + ." filename '".$v_header['stored_filename'] + ."'"); + + return PclZip::errorCode(); + } + } + + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + $v_result = $this->privConvertHeader2FileInfo($v_header, + $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + $v_extract = false; + } + + // ----- Look for real extraction + if ($v_extract) + { + + // ----- Go to the file position + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header['offset'])) + { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + $v_string = ''; + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for extraction in standard output + elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) + && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for normal extraction + else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, + $p_path, $p_remove_path, + $p_remove_all_path, + $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } + + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external']&0x00000010)==0x00000010) { + + $p_entry['status'] = "filtered"; + + return $v_result; + } + + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + } + + // ----- Look for path to remove + else if ($p_remove_path != "") + { + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) + { + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) + { + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + } + } + + // ----- Add the path + if ($p_path != '') { + $p_entry['filename'] = $p_path."/".$p_entry['filename']; + } + + // ----- Check a base_dir_restriction + if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { + $v_inclusion + = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], + $p_entry['filename']); + if ($v_inclusion == 0) { + + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, + "Filename '".$p_entry['filename']."' is " + ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + + return PclZip::errorCode(); + } + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) + { + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, + "Filename '".$p_entry['filename']."' is " + ."already used by an existing directory"); + + return PclZip::errorCode(); + } + } + // ----- Look if file is write protected + else if (!is_writeable($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "write_protected"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Filename '".$p_entry['filename']."' exists " + ."and is write protected"); + + return PclZip::errorCode(); + } + } + + // ----- Look if the extracted file is older + else if (filemtime($p_entry['filename']) > $p_entry['mtime']) + { + // ----- Change the file status + if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) + && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { + } + else { + $p_entry['status'] = "newer_exist"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Newer version of '".$p_entry['filename']."' exists " + ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); + + return PclZip::errorCode(); + } + } + } + else { + } + } + + // ----- Check the directory availability and create it if necessary + else { + if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) + $v_dir_to_check = $p_entry['filename']; + else if (!strstr($p_entry['filename'], "/")) + $v_dir_to_check = ""; + else + $v_dir_to_check = dirname($p_entry['filename']); + + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + //return $v_result; + $v_result = 1; + } + } + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) + { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + return $v_result; + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Closing the destination file + fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + + + } + else { + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); + return PclZip::errorCode(); + } + + + // ----- Look for using temporary file to unzip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { + $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Look for extract in memory + else { + + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === FALSE) { + + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; + + return $v_result; + } + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + return $v_result; + } + + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); + + // ----- Closing the destination file + @fclose($v_dest_file); + + } + + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { + + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } + + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileUsingTempFile(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Creates a temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + + // ----- Write gz file format header + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + @fwrite($v_dest_file, $v_binary_data, 10); + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Write gz file format footer + $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); + @fwrite($v_dest_file, $v_binary_data, 8); + + // ----- Close the temporary file + @fclose($v_dest_file); + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + $p_entry['status'] = "write_error"; + return $v_result; + } + + // ----- Open the temporary gz file + if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { + @fclose($v_dest_file); + $p_entry['status'] = "read_error"; + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($v_src_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + @fclose($v_dest_file); + @gzclose($v_src_file); + + // ----- Delete the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileInOutput(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Trace + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { + + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } + else { + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) + { + $v_result=1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + // if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } + else { + + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === FALSE) { + // TBC + } + } + + // ----- Trace + } + else { + // TBC : error : can not extract a folder in a string + } + + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Swap the content to header + $v_local_header['content'] = $p_string; + $p_string = ''; + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Swap back the content to header + $p_string = $v_local_header['content']; + unset($v_local_header['content']); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } + else { + $p_header['extra'] = ''; + } + + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + $p_header['filename_len'] = $v_data['filename_len']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // TBC + //for(reset($v_data); $key = key($v_data); next($v_data)) { + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadCentralFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + + // ----- Get filename + if ($p_header['filename_len'] != 0) + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + else + $p_header['filename'] = ''; + + // ----- Get extra + if ($p_header['extra_len'] != 0) + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + else + $p_header['extra'] = ''; + + // ----- Get comment + if ($p_header['comment_len'] != 0) + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + else + $p_header['comment'] = ''; + + // ----- Extract properties + + // ----- Recuperate date in UNIX format + //if ($p_header['mdate'] && $p_header['mtime']) + // TBC : bug : this was ignoring time with 0/0/0 + if (1) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set default status to ok + $p_header['status'] = 'ok'; + + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + } + + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + $v_result=1; + + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + } + + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + $p_local_header['size'] = $p_central_header['size']; + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + $p_local_header['crc'] = $p_central_header['crc']; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadEndCentralDir(&$p_central_dir) + { + $v_result=1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + @fseek($this->zip_fd, $v_size); + if (@ftell($this->zip_fd) != $v_size) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->zip_fd, $v_size-22); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = @unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } + + $v_pos = ftell($this->zip_fd); + } + + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) + $v_maximum_size = $v_size; + @fseek($this->zip_fd, $v_size-$v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) + { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + //$v_bytes = ($v_bytes << 8) | Ord($v_byte); + // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number + // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. + $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) + { + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, + 'The central dir is not at the end of the archive.' + .' Some trailing bytes exists after the archive.'); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Get comment + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } + else + $p_central_dir['comment'] = ''; + + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; + + // TBC + //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + //} + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDeleteByRule(&$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + + return $v_result; + } + + + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; + + // ----- Look for the specific extract rules + $v_found = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ + && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + } + // ----- Look for a filename + elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_found = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + else { + $v_found = true; + } + + // ----- Look for deletion + if ($v_found) + { + unset($v_header_list[$v_nb_extracted]); + } + else + { + $v_nb_extracted++; + } + } + + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); + + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Look which file need to be kept + for ($i=0; $izip_fd); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, + $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); + + // ----- Re-Create the Central Dir files header + for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + } + + // ----- Remove every files : reset the file + else if ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { + return $v_result; + } + + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { + return $v_result; + } + + $this->privCloseFd(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + function privDirCheck($p_dir, $p_is_dir=false) + { + $v_result = 1; + + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1)=='/')) + { + $p_dir = substr($p_dir, 0, strlen($p_dir)-1); + } + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) + { + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + + // ----- Just a check + if ($p_parent_dir != $p_dir) + { + // ----- Look for parent directory + if ($p_parent_dir != "") + { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) + { + return $v_result; + } + } + } + + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privMerge(&$p_archive_to_add) + { + $v_result=1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) + { + + // ----- Nothing to merge, so merge is a success + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Look if the archive exists + if (!is_file($this->zipname)) + { + + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Open the archive_to_add file + if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) + { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($p_archive_to_add->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; + + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd)-$v_offset; + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; + + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDuplicate($p_archive_filename) + { + $v_result=1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) + { + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) + { + $this->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorLog($p_error_code=0, $p_error_string='') + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } + else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorReset() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } + else { + $this->error_code = 0; + $this->error_string = ''; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDisableMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); + + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime(0); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privSwapBackMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime($this->magic_quotes_status); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + } + // End of class + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathReduction() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilPathReduction($p_dir) + { + $v_result = ""; + + // ----- Look for not empty path + if ($p_dir != "") { + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i=sizeof($v_list)-1; $i>=0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } + else if ($v_list[$i] == "..") { + $v_skip++; + } + else if ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/".$v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + $v_skip = 0; + } + } + // ----- Last '/' i.e. indicates a directory + else if ($i == (sizeof($v_list)-1)) { + $v_result = $v_list[$i]; + } + // ----- Double '/' inside the path + else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } + else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } + else { + $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../'.$v_result; + $v_skip--; + } + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathInclusion() + // Description : + // This function indicates if the path $p_path is under the $p_dir tree. Or, + // said in an other way, if the file or sub-dir $p_path is inside the dir + // $p_dir. + // The function indicates also if the path is exactly the same as the dir. + // This function supports path with duplicated '/' like '//', but does not + // support '.' or '..' statements. + // Parameters : + // Return Values : + // 0 if $p_path is not inside directory $p_dir + // 1 if $p_path is inside directory $p_dir + // 2 if $p_path is exactly the same as $p_dir + // -------------------------------------------------------------------------------- + function PclZipUtilPathInclusion($p_dir, $p_path) + { + $v_result = 1; + + // ----- Look for path beginning by ./ + if ( ($p_dir == '.') + || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { + $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); + } + if ( ($p_path == '.') + || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); + } + + // ----- Explode dir and path by directory separator + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); + $v_list_path_size = sizeof($v_list_path); + + // ----- Study directories paths + $i = 0; + $j = 0; + while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } + + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } + else if ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilCopyBlock() + // Description : + // Parameters : + // $p_mode : read/write compression mode + // 0 : src & dest normal + // 1 : src gzip, dest normal + // 2 : src normal, dest gzip + // 3 : src & dest gzip + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) + { + $v_result = 1; + + if ($p_mode==0) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==1) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==2) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==3) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilRename() + // Description : + // This function tries to do a simple rename() function. If it fails, it + // tries to copy the $p_src file in a new $p_dest file and then unlink the + // first one. + // Parameters : + // $p_src : Old filename + // $p_dest : New filename + // Return Values : + // 1 on success, 0 on failure. + // -------------------------------------------------------------------------------- + function PclZipUtilRename($p_src, $p_dest) + { + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } + else if (!@unlink($p_src)) { + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilOptionText() + // Description : + // Translate option value in text. Mainly for debug purpose. + // Parameters : + // $p_option : the option value. + // Return Values : + // The option text value. + // -------------------------------------------------------------------------------- + function PclZipUtilOptionText($p_option) + { + + $v_list = get_defined_constants(); + for (reset($v_list); $v_key = key($v_list); next($v_list)) { + $v_prefix = substr($v_key, 0, 10); + if (( ($v_prefix == 'PCLZIP_OPT') + || ($v_prefix == 'PCLZIP_CB_') + || ($v_prefix == 'PCLZIP_ATT')) + && ($v_list[$v_key] == $p_option)) { + return $v_key; + } + } + + $v_result = 'Unknown'; + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilTranslateWinPath() + // Description : + // Translate windows path by replacing '\' by '/' and optionally removing + // drive letter. + // Parameters : + // $p_path : path to translate. + // $p_remove_disk_letter : true | false + // Return Values : + // The path translated. + // -------------------------------------------------------------------------------- + function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) + { + if (stristr(php_uname(), 'windows')) { + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position+1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + return $p_path; + } + // -------------------------------------------------------------------------------- + + +?> diff --git a/libraries/PHPExcel/PHPExcel/Shared/PCLZip/readme.txt b/libraries/PHPExcel/PHPExcel/Shared/PCLZip/readme.txt new file mode 100644 index 000000000..6ed883947 --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Shared/PCLZip/readme.txt @@ -0,0 +1,421 @@ +// -------------------------------------------------------------------------------- +// PclZip 2.8.2 - readme.txt +// -------------------------------------------------------------------------------- +// License GNU/LGPL - August 2009 +// Vincent Blavet - vincent@phpconcept.net +// http://www.phpconcept.net +// -------------------------------------------------------------------------------- +// $Id: readme.txt,v 1.60 2009/09/30 20:35:21 vblavet Exp $ +// -------------------------------------------------------------------------------- + + + +0 - Sommaire +============ + 1 - Introduction + 2 - What's new + 3 - Corrected bugs + 4 - Known bugs or limitations + 5 - License + 6 - Warning + 7 - Documentation + 8 - Author + 9 - Contribute + +1 - Introduction +================ + + PclZip is a library that allow you to manage a Zip archive. + + Full documentation about PclZip can be found here : http://www.phpconcept.net/pclzip + +2 - What's new +============== + + Version 2.8.2 : + - PCLZIP_CB_PRE_EXTRACT and PCLZIP_CB_POST_EXTRACT are now supported with + extraction as a string (PCLZIP_OPT_EXTRACT_AS_STRING). The string + can also be modified in the post-extract call back. + **Bugs correction : + - PCLZIP_OPT_REMOVE_ALL_PATH was not working correctly + - Remove use of eval() and do direct call to callback functions + - Correct support of 64bits systems (Thanks to WordPress team) + + Version 2.8.1 : + - Move option PCLZIP_OPT_BY_EREG to PCLZIP_OPT_BY_PREG because ereg() is + deprecated in PHP 5.3. When using option PCLZIP_OPT_BY_EREG, PclZip will + automatically replace it by PCLZIP_OPT_BY_PREG. + + Version 2.8 : + - Improve extraction of zip archive for large files by using temporary files + This feature is working like the one defined in r2.7. + Options are renamed : PCLZIP_OPT_TEMP_FILE_ON, PCLZIP_OPT_TEMP_FILE_OFF, + PCLZIP_OPT_TEMP_FILE_THRESHOLD + - Add a ratio constant PCLZIP_TEMPORARY_FILE_RATIO to configure the auto + sense of temporary file use. + - Bug correction : Reduce filepath in returned file list to remove ennoying + './/' preambule in file path. + + Version 2.7 : + - Improve creation of zip archive for large files : + PclZip will now autosense the configured memory and use temporary files + when large file is suspected. + This feature can also ne triggered by manual options in create() and add() + methods. 'PCLZIP_OPT_ADD_TEMP_FILE_ON' force the use of temporary files, + 'PCLZIP_OPT_ADD_TEMP_FILE_OFF' disable the autosense technic, + 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD' allow for configuration of a size + threshold to use temporary files. + Using "temporary files" rather than "memory" might take more time, but + might give the ability to zip very large files : + Tested on my win laptop with a 88Mo file : + Zip "in-memory" : 18sec (max_execution_time=30, memory_limit=180Mo) + Zip "tmporary-files" : 23sec (max_execution_time=30, memory_limit=30Mo) + - Replace use of mktime() by time() to limit the E_STRICT error messages. + - Bug correction : When adding files with full windows path (drive letter) + PclZip is now working. Before, if the drive letter is not the default + path, PclZip was not able to add the file. + + Version 2.6 : + - Code optimisation + - New attributes PCLZIP_ATT_FILE_COMMENT gives the ability to + add a comment for a specific file. (Don't really know if this is usefull) + - New attribute PCLZIP_ATT_FILE_CONTENT gives the ability to add a string + as a file. + - New attribute PCLZIP_ATT_FILE_MTIME modify the timestamp associated with + a file. + - Correct a bug. Files archived with a timestamp with 0h0m0s were extracted + with current time + - Add CRC value in the informations returned back for each file after an + action. + - Add missing closedir() statement. + - When adding a folder, and removing the path of this folder, files were + incorrectly added with a '/' at the beginning. Which means files are + related to root in unix systems. Corrected. + - Add conditional if before constant definition. This will allow users + to redefine constants without changing the file, and then improve + upgrade of pclzip code for new versions. + + Version 2.5 : + - Introduce the ability to add file/folder with individual properties (file descriptor). + This gives for example the ability to change the filename of a zipped file. + . Able to add files individually + . Able to change full name + . Able to change short name + . Compatible with global options + - New attributes : PCLZIP_ATT_FILE_NAME, PCLZIP_ATT_FILE_NEW_SHORT_NAME, PCLZIP_ATT_FILE_NEW_FULL_NAME + - New error code : PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE + - Add a security control feature. PclZip can extract any file in any folder + of a system. People may use this to upload a zip file and try to override + a system file. The PCLZIP_OPT_EXTRACT_DIR_RESTRICTION will give the + ability to forgive any directory transversal behavior. + - New PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : check extraction path + - New error code : PCLZIP_ERR_DIRECTORY_RESTRICTION + - Modification in PclZipUtilPathInclusion() : dir and path beginning with ./ will be prepend + by current path (getcwd()) + + Version 2.4 : + - Code improvment : try to speed up the code by removing unusefull call to pack() + - Correct bug in delete() : delete() should be called with no argument. This was not + the case in 2.3. This is corrected in 2.4. + - Correct a bug in path_inclusion function. When the path has several '../../', the + result was bad. + - Add a check for magic_quotes_runtime configuration. If enabled, PclZip will + disable it while working and det it back to its original value. + This resolve a lots of bad formated archive errors. + - Bug correction : PclZip now correctly unzip file in some specific situation, + when compressed content has same size as uncompressed content. + - Bug correction : When selecting option 'PCLZIP_OPT_REMOVE_ALL_PATH', + directories are not any more created. + - Code improvment : correct unclosed opendir(), better handling of . and .. in + loops. + + + Version 2.3 : + - Correct a bug with PHP5 : affecting the value 0xFE49FFE0 to a variable does not + give the same result in PHP4 and PHP5 .... + + Version 2.2 : + - Try development of PCLZIP_OPT_CRYPT ..... + However this becomes to a stop. To crypt/decrypt I need to multiply 2 long integers, + the result (greater than a long) is not supported by PHP. Even the use of bcmath + functions does not help. I did not find yet a solution ...; + - Add missing '/' at end of directory entries + - Check is a file is encrypted or not. Returns status 'unsupported_encryption' and/or + error code PCLZIP_ERR_UNSUPPORTED_ENCRYPTION. + - Corrected : Bad "version need to extract" field in local file header + - Add private method privCheckFileHeaders() in order to check local and central + file headers. PclZip is now supporting purpose bit flag bit 3. Purpose bit flag bit 3 gives + the ability to have a local file header without size, compressed size and crc filled. + - Add a generic status 'error' for file status + - Add control of compression type. PclZip only support deflate compression method. + Before v2.2, PclZip does not check the compression method used in an archive while + extracting. With v2.2 PclZip returns a new error status for a file using an unsupported + compression method. New status is "unsupported_compression". New error code is + PCLZIP_ERR_UNSUPPORTED_COMPRESSION. + - Add optional attribute PCLZIP_OPT_STOP_ON_ERROR. This will stop the extract of files + when errors like 'a folder with same name exists' or 'a newer file exists' or + 'a write protected file' exists, rather than set a status for the concerning file + and resume the extract of the zip. + - Add optional attribute PCLZIP_OPT_REPLACE_NEWER. This will force, during an extract' the + replacement of the file, even if a newer version of the file exists. + Note that today if a file with the same name already exists but is older it will be + replaced by the extracted one. + - Improve PclZipUtilOption() + - Support of zip archive with trailing bytes. Before 2.2, PclZip checks that the central + directory structure is the last data in the archive. Crypt encryption/decryption of + zip archive put trailing 0 bytes after decryption. PclZip is now supporting this. + + Version 2.1 : + - Add the ability to abort the extraction by using a user callback function. + The user can now return the value '2' in its callback which indicates to stop the + extraction. For a pre call-back extract is stopped before the extration of the current + file. For a post call back, the extraction is stopped after. + - Add the ability to extract a file (or several files) directly in the standard output. + This is done by the new parameter PCLZIP_OPT_EXTRACT_IN_OUTPUT with method extract(). + - Add support for parameters PCLZIP_OPT_COMMENT, PCLZIP_OPT_ADD_COMMENT, + PCLZIP_OPT_PREPEND_COMMENT. This will create, replace, add, or prepend comments + in the zip archive. + - When merging two archives, the comments are not any more lost, but merged, with a + blank space separator. + - Corrected bug : Files are not deleted when all files are asked to be deleted. + - Corrected bug : Folders with name '0' made PclZip to abort the create or add feature. + + + Version 2.0 : + ***** Warning : Some new features may break the backward compatibility for your scripts. + Please carefully read the readme file. + - Add the ability to delete by Index, name and regular expression. This feature is + performed by the method delete(), which uses the optional parameters + PCLZIP_OPT_BY_INDEX, PCLZIP_OPT_BY_NAME, PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG. + - Add the ability to extract by regular expression. To extract by regexp you must use the method + extract(), with the option PCLZIP_OPT_BY_EREG or PCLZIP_OPT_BY_PREG + (depending if you want to use ereg() or preg_match() syntax) followed by the + regular expression pattern. + - Add the ability to extract by index, directly with the extract() method. This is a + code improvment of the extractByIndex() method. + - Add the ability to extract by name. To extract by name you must use the method + extract(), with the option PCLZIP_OPT_BY_NAME followed by the filename to + extract or an array of filenames to extract. To extract all a folder, use the folder + name rather than the filename with a '/' at the end. + - Add the ability to add files without compression. This is done with a new attribute + which is PCLZIP_OPT_NO_COMPRESSION. + - Add the attribute PCLZIP_OPT_EXTRACT_AS_STRING, which allow to extract a file directly + in a string without using any file (or temporary file). + - Add constant PCLZIP_SEPARATOR for static configuration of filename separators in a single string. + The default separator is now a comma (,) and not any more a blank space. + THIS BREAK THE BACKWARD COMPATIBILITY : Please check if this may have an impact with + your script. + - Improve algorythm performance by removing the use of temporary files when adding or + extracting files in an archive. + - Add (correct) detection of empty filename zipping. This can occurs when the removed + path is the same + as a zipped dir. The dir is not zipped (['status'] = filtered), only its content. + - Add better support for windows paths (thanks for help from manus@manusfreedom.com). + - Corrected bug : When the archive file already exists with size=0, the add() method + fails. Corrected in 2.0. + - Remove the use of OS_WINDOWS constant. Use php_uname() function rather. + - Control the order of index ranges in extract by index feature. + - Change the internal management of folders (better handling of internal flag). + + + Version 1.3 : + - Removing the double include check. This is now done by include_once() and require_once() + PHP directives. + - Changing the error handling mecanism : Remove the use of an external error library. + The former PclError...() functions are replaced by internal equivalent methods. + By changing the environment variable PCLZIP_ERROR_EXTERNAL you can still use the former library. + Introducing the use of constants for error codes rather than integer values. This will help + in futur improvment. + Introduction of error handling functions like errorCode(), errorName() and errorInfo(). + - Remove the deprecated use of calling function with arguments passed by reference. + - Add the calling of extract(), extractByIndex(), create() and add() functions + with variable options rather than fixed arguments. + - Add the ability to remove all the file path while extracting or adding, + without any need to specify the path to remove. + This is available for extract(), extractByIndex(), create() and add() functionS by using + the new variable options parameters : + - PCLZIP_OPT_REMOVE_ALL_PATH : by indicating this option while calling the fct. + - Ability to change the mode of a file after the extraction (chmod()). + This is available for extract() and extractByIndex() functionS by using + the new variable options parameters. + - PCLZIP_OPT_SET_CHMOD : by setting the value of this option. + - Ability to definition call-back options. These call-back will be called during the adding, + or the extracting of file (extract(), extractByIndex(), create() and add() functions) : + - PCLZIP_CB_PRE_EXTRACT : will be called before each extraction of a file. The user + can trigerred the change the filename of the extracted file. The user can triggered the + skip of the extraction. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_EXTRACT : will be called after each extraction of a file. + Nothing can be triggered from that point. + - PCLZIP_CB_PRE_ADD : will be called before each add of a file. The user + can trigerred the change the stored filename of the added file. The user can triggered the + skip of the add. This is adding a 'skipped' status in the file list result value. + - PCLZIP_CB_POST_ADD : will be called after each add of a file. + Nothing can be triggered from that point. + - Two status are added in the file list returned as function result : skipped & filename_too_long + 'skipped' is used when a call-back function ask for skipping the file. + 'filename_too_long' is used while adding a file with a too long filename to archive (the file is + not added) + - Adding the function PclZipUtilPathInclusion(), that check the inclusion of a path into + a directory. + - Add a check of the presence of the archive file before some actions (like list, ...) + - Add the initialisation of field "index" in header array. This means that by + default index will be -1 when not explicitly set by the methods. + + Version 1.2 : + - Adding a duplicate function. + - Adding a merge function. The merge function is a "quick merge" function, + it just append the content of an archive at the end of the first one. There + is no check for duplicate files or more recent files. + - Improve the search of the central directory end. + + Version 1.1.2 : + + - Changing the license of PclZip. PclZip is now released under the GNU / LGPL license + (see License section). + - Adding the optional support of a static temporary directory. You will need to configure + the constant PCLZIP_TEMPORARY_DIR if you want to use this feature. + - Improving the rename() function. In some cases rename() does not work (different + Filesystems), so it will be replaced by a copy() + unlink() functions. + + Version 1.1.1 : + + - Maintenance release, no new feature. + + Version 1.1 : + + - New method Add() : adding files in the archive + - New method ExtractByIndex() : partial extract of the archive, files are identified by + their index in the archive + - New method DeleteByIndex() : delete some files/folder entries from the archive, + files are identified by their index in the archive. + - Adding a test of the zlib extension presence. If not present abort the script. + + Version 1.0.1 : + + - No new feature + + +3 - Corrected bugs +================== + + Corrected in Version 2.0 : + - Corrected : During an extraction, if a call-back fucntion is used and try to skip + a file, all the extraction process is stopped. + + Corrected in Version 1.3 : + - Corrected : Support of static synopsis for method extract() is broken. + - Corrected : invalid size of archive content field (0xFF) should be (0xFFFF). + - Corrected : When an extract is done with a remove_path parameter, the entry for + the directory with exactly the same path is not skipped/filtered. + - Corrected : extractByIndex() and deleteByIndex() were not managing index in the + right way. For example indexes '1,3-5,11' will only extract files 1 and 11. This + is due to a sort of the index resulting table that puts 11 before 3-5 (sort on + string and not interger). The sort is temporarilly removed, this means that + you must provide a sorted list of index ranges. + + Corrected in Version 1.2 : + + - Nothing. + + Corrected in Version 1.1.2 : + + - Corrected : Winzip is unable to delete or add new files in a PclZip created archives. + + Corrected in Version 1.1.1 : + + - Corrected : When archived file is not compressed (0% compression), the + extract method fails. + + Corrected in Version 1.1 : + + - Corrected : Adding a complete tree of folder may result in a bad archive + creation. + + Corrected in Version 1.0.1 : + + - Corrected : Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + + +4 - Known bugs or limitations +============================= + + Please publish bugs reports in SourceForge : + http://sourceforge.net/tracker/?group_id=40254&atid=427564 + + In Version 2.x : + - PclZip does only support file uncompressed or compressed with deflate (compression method 8) + - PclZip does not support password protected zip archive + - Some concern were seen when changing mtime of a file while archiving. + Seems to be linked to Daylight Saving Time (PclTest_changing_mtime). + + In Version 1.2 : + + - merge() methods does not check for duplicate files or last date of modifications. + + In Version 1.1 : + + - Limitation : Using 'extract' fields in the file header in the zip archive is not supported. + - WinZip is unable to delete a single file in a PclZip created archive. It is also unable to + add a file in a PclZip created archive. (Corrected in v.1.2) + + In Version 1.0.1 : + + - Adding a complete tree of folder may result in a bad archive + creation. (Corrected in V.1.1). + - Path given to methods must be in the unix format (/) and not the Windows format (\). + Workaround : Use only / directory separators. + - PclZip is using temporary files that are sometime the name of the file with a .tmp or .gz + added suffix. Files with these names may already exist and may be overwritten. + Workaround : none. + - PclZip does not check if the zlib extension is present. If it is absent, the zip + file is not created and the lib abort without warning. + Workaround : enable the zlib extension on the php install + + In Version 1.0 : + + - Error while compressing files greater than PCLZIP_READ_BLOCK_SIZE (default=1024). + (Corrected in v.1.0.1) + - Limitation : Multi-disk zip archive are not supported. + + +5 - License +=========== + + Since version 1.1.2, PclZip Library is released under GNU/LGPL license. + This library is free, so you can use it at no cost. + + HOWEVER, if you release a script, an application, a library or any kind of + code using PclZip library (or a part of it), YOU MUST : + - Indicate in the documentation (or a readme file), that your work + uses PclZip Library, and make a reference to the author and the web site + http://www.phpconcept.net + - Gives the ability to the final user to update the PclZip libary. + + I will also appreciate that you send me a mail (vincent@phpconcept.net), just to + be aware that someone is using PclZip. + + For more information about GNU/LGPL license : http://www.gnu.org + +6 - Warning +================= + + This library and the associated files are non commercial, non professional work. + It should not have unexpected results. However if any damage is caused by this software + the author can not be responsible. + The use of this software is at the risk of the user. + +7 - Documentation +================= + PclZip User Manuel is available in English on PhpConcept : http://www.phpconcept.net/pclzip/man/en/index.php + A Russian translation was done by Feskov Kuzma : http://php.russofile.ru/ru/authors/unsort/zip/ + +8 - Author +========== + + This software was written by Vincent Blavet (vincent@phpconcept.net) on its leasure time. + +9 - Contribute +============== + If you want to contribute to the development of PclZip, please contact vincent@phpconcept.net. + If you can help in financing PhpConcept hosting service, please go to + http://www.phpconcept.net/soutien.php diff --git a/libraries/PHPExcel/PHPExcel/Shared/PasswordHasher.php b/libraries/PHPExcel/PHPExcel/Shared/PasswordHasher.php index 7fb493494..49ffcef0e 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/PasswordHasher.php +++ b/libraries/PHPExcel/PHPExcel/Shared/PasswordHasher.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_PasswordHasher { diff --git a/libraries/PHPExcel/PHPExcel/Shared/String.php b/libraries/PHPExcel/PHPExcel/Shared/String.php index c033b9ad0..aab02f1cd 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/String.php +++ b/libraries/PHPExcel/PHPExcel/Shared/String.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_String { @@ -69,6 +69,13 @@ class PHPExcel_Shared_String */ private static $_thousandsSeparator; + /** + * Currency code + * + * @var string + */ + private static $_currencyCode; + /** * Is mbstring extension avalable? * @@ -303,7 +310,7 @@ class PHPExcel_Shared_String // Sometimes iconv_substr('A', 0, 1, 'UTF-8') just returns false in PHP 5.2.0 // we cannot use iconv in that case either (http://bugs.php.net/bug.php?id=37773) - if (!@iconv('UTF-8', 'UTF-16LE', 'x')) { + if (!@iconv_substr('A', 0, 1, 'UTF-8')) { self::$_isIconvEnabled = false; return false; } @@ -322,6 +329,15 @@ class PHPExcel_Shared_String return true; } + public static function buildCharacterSets() { + if(empty(self::$_controlCharacters)) { + self::_buildControlCharacters(); + } + if(empty(self::$_SYLKCharacters)) { + self::_buildSYLKCharacters(); + } + } + /** * Convert from OpenXML escaped control character to PHP control character * @@ -337,10 +353,6 @@ class PHPExcel_Shared_String * @return string */ public static function ControlCharacterOOXML2PHP($value = '') { - if(empty(self::$_controlCharacters)) { - self::_buildControlCharacters(); - } - return str_replace( array_keys(self::$_controlCharacters), array_values(self::$_controlCharacters), $value ); } @@ -359,10 +371,6 @@ class PHPExcel_Shared_String * @return string */ public static function ControlCharacterPHP2OOXML($value = '') { - if(empty(self::$_controlCharacters)) { - self::_buildControlCharacters(); - } - return str_replace( array_values(self::$_controlCharacters), array_keys(self::$_controlCharacters), $value ); } @@ -491,7 +499,7 @@ class PHPExcel_Shared_String // else, no conversion return $value; } - + /** * Decode UTF-16 encoded strings. * @@ -533,18 +541,15 @@ class PHPExcel_Shared_String public static function CountCharacters($value, $enc = 'UTF-8') { if (self::getIsIconvEnabled()) { - $count = iconv_strlen($value, $enc); - return $count; + return iconv_strlen($value, $enc); } if (self::getIsMbstringEnabled()) { - $count = mb_strlen($value, $enc); - return $count; + return mb_strlen($value, $enc); } // else strlen - $count = strlen($value); - return $count; + return strlen($value); } /** @@ -558,18 +563,15 @@ class PHPExcel_Shared_String public static function Substring($pValue = '', $pStart = 0, $pLength = 0) { if (self::getIsIconvEnabled()) { - $string = iconv_substr($pValue, $pStart, $pLength, 'UTF-8'); - return $string; + return iconv_substr($pValue, $pStart, $pLength, 'UTF-8'); } if (self::getIsMbstringEnabled()) { - $string = mb_substr($pValue, $pStart, $pLength, 'UTF-8'); - return $string; + return mb_substr($pValue, $pStart, $pLength, 'UTF-8'); } // else substr - $string = substr($pValue, $pStart, $pLength); - return $string; + return substr($pValue, $pStart, $pLength); } @@ -602,9 +604,8 @@ class PHPExcel_Shared_String $localeconv = localeconv(); self::$_decimalSeparator = $localeconv['decimal_point'] != '' ? $localeconv['decimal_point'] : $localeconv['mon_decimal_point']; - - if (self::$_decimalSeparator == '') - { + + if (self::$_decimalSeparator == '') { // Default to . self::$_decimalSeparator = '.'; } @@ -650,6 +651,38 @@ class PHPExcel_Shared_String self::$_thousandsSeparator = $pValue; } + /** + * Get the currency code. If it has not yet been set explicitly, try to obtain the + * symbol information from locale. + * + * @return string + */ + public static function getCurrencyCode() + { + if (!isset(self::$_currencyCode)) { + $localeconv = localeconv(); + self::$_currencyCode = $localeconv['currency_symbol'] != '' + ? $localeconv['currency_symbol'] : $localeconv['int_curr_symbol']; + + if (self::$_currencyCode == '') { + // Default to $ + self::$_currencyCode = '$'; + } + } + return self::$_currencyCode; + } + + /** + * Set the currency code. Only used by PHPExcel_Style_NumberFormat::toFormattedString() + * to format output by PHPExcel_Writer_HTML and PHPExcel_Writer_PDF + * + * @param string $pValue Character for currency code + */ + public static function setCurrencyCode($pValue = '$') + { + self::$_currencyCode = $pValue; + } + /** * Convert SYLK encoded string to UTF-8 * @@ -663,10 +696,6 @@ class PHPExcel_Shared_String return $pValue; } - if(empty(self::$_SYLKCharacters)) { - self::_buildSYLKCharacters(); - } - foreach (self::$_SYLKCharacters as $k => $v) { $pValue = str_replace($k, $v, $pValue); } diff --git a/libraries/PHPExcel/PHPExcel/Shared/XMLWriter.php b/libraries/PHPExcel/PHPExcel/Shared/XMLWriter.php index 8514847c3..96ef1b411 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/XMLWriter.php +++ b/libraries/PHPExcel/PHPExcel/Shared/XMLWriter.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Shared + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ if (!defined('DATE_W3C')) { @@ -38,21 +38,14 @@ if (!defined('DEBUGMODE_ENABLED')) { * PHPExcel_Shared_XMLWriter * * @category PHPExcel - * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Shared + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ -class PHPExcel_Shared_XMLWriter { +class PHPExcel_Shared_XMLWriter extends XMLWriter { /** Temporary storage method */ const STORAGE_MEMORY = 1; const STORAGE_DISK = 2; - /** - * Internal XMLWriter - * - * @var XMLWriter - */ - private $_xmlWriter; - /** * Temporary filename * @@ -66,83 +59,63 @@ class PHPExcel_Shared_XMLWriter { * @param int $pTemporaryStorage Temporary storage location * @param string $pTemporaryStorageFolder Temporary storage folder */ - public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = './') { - // Create internal XMLWriter - $this->_xmlWriter = new XMLWriter(); + public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = './') { + // Open temporary storage + if ($pTemporaryStorage == self::STORAGE_MEMORY) { + $this->openMemory(); + } else { + // Create temporary filename + $this->_tempFileName = @tempnam($pTemporaryStorageFolder, 'xml'); - // Open temporary storage - if ($pTemporaryStorage == self::STORAGE_MEMORY) { - $this->_xmlWriter->openMemory(); - } else { - // Create temporary filename - $this->_tempFileName = @tempnam($pTemporaryStorageFolder, 'xml'); + // Open storage + if ($this->openUri($this->_tempFileName) === false) { + // Fallback to memory... + $this->openMemory(); + } + } - // Open storage - if ($this->_xmlWriter->openUri($this->_tempFileName) === false) { - // Fallback to memory... - $this->_xmlWriter->openMemory(); - } - } - - // Set default values + // Set default values if (DEBUGMODE_ENABLED) { - $this->_xmlWriter->setIndent(true); - } - } + $this->setIndent(true); + } + } - /** - * Destructor - */ - public function __destruct() { - // Desctruct XMLWriter - unset($this->_xmlWriter); + /** + * Destructor + */ + public function __destruct() { + // Unlink temporary files + if ($this->_tempFileName != '') { + @unlink($this->_tempFileName); + } + } - // Unlink temporary files - if ($this->_tempFileName != '') { - @unlink($this->_tempFileName); - } - } + /** + * Get written data + * + * @return $data + */ + public function getData() { + if ($this->_tempFileName == '') { + return $this->outputMemory(true); + } else { + $this->flush(); + return file_get_contents($this->_tempFileName); + } + } - /** - * Get written data - * - * @return $data - */ - public function getData() { - if ($this->_tempFileName == '') { - return $this->_xmlWriter->outputMemory(true); - } else { - $this->_xmlWriter->flush(); - return file_get_contents($this->_tempFileName); - } - } + /** + * Fallback method for writeRaw, introduced in PHP 5.2 + * + * @param string $text + * @return string + */ + public function writeRawData($text) + { + if (method_exists($this, 'writeRaw')) { + return $this->writeRaw(htmlspecialchars($text)); + } - /** - * Catch function calls (and pass them to internal XMLWriter) - * - * @param unknown_type $function - * @param unknown_type $args - */ - public function __call($function, $args) { - try { - @call_user_func_array(array($this->_xmlWriter, $function), $args); - } catch (Exception $ex) { - // Do nothing! - } - } - - /** - * Fallback method for writeRaw, introduced in PHP 5.2 - * - * @param string $text - * @return string - */ - public function writeRaw($text) - { - if (isset($this->_xmlWriter) && is_object($this->_xmlWriter) && (method_exists($this->_xmlWriter, 'writeRaw'))) { - return $this->_xmlWriter->writeRaw(htmlspecialchars($text)); - } - - return $this->text($text); - } + return $this->text($text); + } } diff --git a/libraries/PHPExcel/PHPExcel/Shared/ZipArchive.php b/libraries/PHPExcel/PHPExcel/Shared/ZipArchive.php new file mode 100644 index 000000000..559f166a6 --- /dev/null +++ b/libraries/PHPExcel/PHPExcel/Shared/ZipArchive.php @@ -0,0 +1,90 @@ +_tempDir = PHPExcel_Shared_File::sys_get_temp_dir(); + + $this->_zip = new PclZip($fileName); + + return true; + } + + + public function close() + { + } + + + public function addFromString($localname, $contents) + { + $filenameParts = pathinfo($localname); + + $handle = fopen($this->_tempDir.'/'.$filenameParts["basename"], "wb"); + fwrite($handle, $contents); + fclose($handle); + + $res = $this->_zip->add($this->_tempDir.'/'.$filenameParts["basename"], + PCLZIP_OPT_REMOVE_PATH, $this->_tempDir, + PCLZIP_OPT_ADD_PATH, $filenameParts["dirname"] + ); + if ($res == 0) { + throw new Exception("Error zipping files : " . $this->_zip->errorInfo(true)); + } + + unlink($this->_tempDir.'/'.$filenameParts["basename"]); + } + +} diff --git a/libraries/PHPExcel/PHPExcel/Shared/ZipStreamWrapper.php b/libraries/PHPExcel/PHPExcel/Shared/ZipStreamWrapper.php index b79bfc895..06df19ded 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/ZipStreamWrapper.php +++ b/libraries/PHPExcel/PHPExcel/Shared/ZipStreamWrapper.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Shared_ZipStreamWrapper { /** diff --git a/libraries/PHPExcel/PHPExcel/Shared/trend/bestFitClass.php b/libraries/PHPExcel/PHPExcel/Shared/trend/bestFitClass.php index 28fe72571..4224d4ffb 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/trend/bestFitClass.php +++ b/libraries/PHPExcel/PHPExcel/Shared/trend/bestFitClass.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Best_Fit { diff --git a/libraries/PHPExcel/PHPExcel/Shared/trend/exponentialBestFitClass.php b/libraries/PHPExcel/PHPExcel/Shared/trend/exponentialBestFitClass.php index 0ff98cc5b..b2a3b3313 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/trend/exponentialBestFitClass.php +++ b/libraries/PHPExcel/PHPExcel/Shared/trend/exponentialBestFitClass.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -34,7 +34,7 @@ require_once(PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/bestFitClass.php'); * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Exponential_Best_Fit extends PHPExcel_Best_Fit { diff --git a/libraries/PHPExcel/PHPExcel/Shared/trend/linearBestFitClass.php b/libraries/PHPExcel/PHPExcel/Shared/trend/linearBestFitClass.php index 71219a07f..19a864113 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/trend/linearBestFitClass.php +++ b/libraries/PHPExcel/PHPExcel/Shared/trend/linearBestFitClass.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -34,7 +34,7 @@ require_once(PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/bestFitClass.php'); * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Linear_Best_Fit extends PHPExcel_Best_Fit { diff --git a/libraries/PHPExcel/PHPExcel/Shared/trend/logarithmicBestFitClass.php b/libraries/PHPExcel/PHPExcel/Shared/trend/logarithmicBestFitClass.php index 03c7dc302..e5d98516c 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/trend/logarithmicBestFitClass.php +++ b/libraries/PHPExcel/PHPExcel/Shared/trend/logarithmicBestFitClass.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -34,7 +34,7 @@ require_once(PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/bestFitClass.php'); * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Logarithmic_Best_Fit extends PHPExcel_Best_Fit { diff --git a/libraries/PHPExcel/PHPExcel/Shared/trend/polynomialBestFitClass.php b/libraries/PHPExcel/PHPExcel/Shared/trend/polynomialBestFitClass.php index 6947c111b..e16e2002a 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/trend/polynomialBestFitClass.php +++ b/libraries/PHPExcel/PHPExcel/Shared/trend/polynomialBestFitClass.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -35,7 +35,7 @@ require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/Matrix.php'; * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Polynomial_Best_Fit extends PHPExcel_Best_Fit { diff --git a/libraries/PHPExcel/PHPExcel/Shared/trend/powerBestFitClass.php b/libraries/PHPExcel/PHPExcel/Shared/trend/powerBestFitClass.php index 6d2281cc1..bb82423d3 100644 --- a/libraries/PHPExcel/PHPExcel/Shared/trend/powerBestFitClass.php +++ b/libraries/PHPExcel/PHPExcel/Shared/trend/powerBestFitClass.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -34,7 +34,7 @@ require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/trend/bestFitClass.php'; * * @category PHPExcel * @package PHPExcel_Shared_Best_Fit - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Power_Best_Fit extends PHPExcel_Best_Fit { diff --git a/libraries/PHPExcel/PHPExcel/Style.php b/libraries/PHPExcel/PHPExcel/Style.php index 3e84f9f09..4cf468c9c 100644 --- a/libraries/PHPExcel/PHPExcel/Style.php +++ b/libraries/PHPExcel/PHPExcel/Style.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style implements PHPExcel_IComparable { @@ -169,14 +169,12 @@ class PHPExcel_Style implements PHPExcel_IComparable $selectedCell = $this->getActiveCell(); // e.g. 'A1' if ($activeSheet->cellExists($selectedCell)) { - $cell = $activeSheet->getCell($selectedCell); - $xfIndex = $cell->getXfIndex(); + $xfIndex = $activeSheet->getCell($selectedCell)->getXfIndex(); } else { $xfIndex = 0; } - $activeStyle = $this->_parent->getCellXfByIndex($xfIndex); - return $activeStyle; + return $this->_parent->getCellXfByIndex($xfIndex); } /** @@ -270,8 +268,6 @@ class PHPExcel_Style implements PHPExcel_IComparable $pRange = strtoupper($pRange); // Is it a cell range or a single cell? - $rangeA = ''; - $rangeB = ''; if (strpos($pRange, ':') === false) { $rangeA = $pRange; $rangeB = $pRange; @@ -610,9 +606,7 @@ class PHPExcel_Style implements PHPExcel_IComparable */ public function setConditionalStyles($pValue = null) { if (is_array($pValue)) { - foreach (PHPExcel_Cell::extractAllCellReferencesInRange($this->getSelectedCells()) as $cellReference) { - $this->getActiveSheet()->setConditionalStyles($cellReference, $pValue); - } + $this->getActiveSheet()->setConditionalStyles($this->getSelectedCells(), $pValue); } return $this; } @@ -638,13 +632,13 @@ class PHPExcel_Style implements PHPExcel_IComparable } return md5( - $this->getFill()->getHashCode() - . $this->getFont()->getHashCode() - . $this->getBorders()->getHashCode() - . $this->getAlignment()->getHashCode() - . $this->getNumberFormat()->getHashCode() + $this->_fill->getHashCode() + . $this->_font->getHashCode() + . $this->_borders->getHashCode() + . $this->_alignment->getHashCode() + . $this->_numberFormat->getHashCode() . $hashConditionals - . $this->getProtection()->getHashCode() + . $this->_protection->getHashCode() . __CLASS__ ); } diff --git a/libraries/PHPExcel/PHPExcel/Style/Alignment.php b/libraries/PHPExcel/PHPExcel/Style/Alignment.php index 15b6c87b8..a274ae0d1 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Alignment.php +++ b/libraries/PHPExcel/PHPExcel/Style/Alignment.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Style_Alignment * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Alignment implements PHPExcel_IComparable { @@ -54,42 +54,42 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable * * @var string */ - private $_horizontal; + private $_horizontal = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL; /** * Vertical * * @var string */ - private $_vertical; + private $_vertical = PHPExcel_Style_Alignment::VERTICAL_BOTTOM; /** * Text rotation * * @var int */ - private $_textRotation; + private $_textRotation = 0; /** * Wrap text * * @var boolean */ - private $_wrapText; + private $_wrapText = false; /** * Shrink to fit * * @var boolean */ - private $_shrinkToFit; + private $_shrinkToFit = false; /** * Indent - only possible with horizontal alignment left and right * * @var int */ - private $_indent; + private $_indent = 0; /** * Parent Borders @@ -112,22 +112,14 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable */ private $_parent; - /** - * Create a new PHPExcel_Style_Alignment - */ - public function __construct($isSupervisor = false) - { - // Supervisor? + /** + * Create a new PHPExcel_Style_Alignment + */ + public function __construct($isSupervisor = false) + { + // Supervisor? $this->_isSupervisor = $isSupervisor; - - // Initialise values - $this->_horizontal = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL; - $this->_vertical = PHPExcel_Style_Alignment::VERTICAL_BOTTOM; - $this->_textRotation = 0; - $this->_wrapText = false; - $this->_shrinkToFit = false; - $this->_indent = 0; - } + } /** * Bind parent. Only used for supervisor @@ -205,24 +197,24 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable return array('alignment' => $array); } - /** - * Apply styles from array - * - * - * $objPHPExcel->getActiveSheet()->getStyle('B2')->getAlignment()->applyFromArray( - * array( - * 'horizontal' => PHPExcel_Style_Alignment::HORIZONTAL_CENTER, - * 'vertical' => PHPExcel_Style_Alignment::VERTICAL_CENTER, - * 'rotation' => 0, - * 'wrap' => true - * ) - * ); - * - * - * @param array $pStyles Array containing style information - * @throws Exception - * @return PHPExcel_Style_Alignment - */ + /** + * Apply styles from array + * + * + * $objPHPExcel->getActiveSheet()->getStyle('B2')->getAlignment()->applyFromArray( + * array( + * 'horizontal' => PHPExcel_Style_Alignment::HORIZONTAL_CENTER, + * 'vertical' => PHPExcel_Style_Alignment::VERTICAL_CENTER, + * 'rotation' => 0, + * 'wrap' => true + * ) + * ); + * + * + * @param array $pStyles Array containing style information + * @throws Exception + * @return PHPExcel_Style_Alignment + */ public function applyFromArray($pStyles = null) { if (is_array($pStyles)) { if ($this->_isSupervisor) { @@ -253,28 +245,28 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable return $this; } - /** - * Get Horizontal - * - * @return string - */ - public function getHorizontal() { + /** + * Get Horizontal + * + * @return string + */ + public function getHorizontal() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getHorizontal(); } - return $this->_horizontal; - } + return $this->_horizontal; + } - /** - * Set Horizontal - * - * @param string $pValue - * @return PHPExcel_Style_Alignment - */ - public function setHorizontal($pValue = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL) { - if ($pValue == '') { - $pValue = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL; - } + /** + * Set Horizontal + * + * @param string $pValue + * @return PHPExcel_Style_Alignment + */ + public function setHorizontal($pValue = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL) { + if ($pValue == '') { + $pValue = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('horizontal' => $pValue)); @@ -284,30 +276,30 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable $this->_horizontal = $pValue; } return $this; - } + } - /** - * Get Vertical - * - * @return string - */ - public function getVertical() { + /** + * Get Vertical + * + * @return string + */ + public function getVertical() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getVertical(); } - return $this->_vertical; - } + return $this->_vertical; + } - /** - * Set Vertical - * - * @param string $pValue - * @return PHPExcel_Style_Alignment - */ - public function setVertical($pValue = PHPExcel_Style_Alignment::VERTICAL_BOTTOM) { - if ($pValue == '') { - $pValue = PHPExcel_Style_Alignment::VERTICAL_BOTTOM; - } + /** + * Set Vertical + * + * @param string $pValue + * @return PHPExcel_Style_Alignment + */ + public function setVertical($pValue = PHPExcel_Style_Alignment::VERTICAL_BOTTOM) { + if ($pValue == '') { + $pValue = PHPExcel_Style_Alignment::VERTICAL_BOTTOM; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('vertical' => $pValue)); @@ -316,70 +308,70 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable $this->_vertical = $pValue; } return $this; - } + } - /** - * Get TextRotation - * - * @return int - */ - public function getTextRotation() { + /** + * Get TextRotation + * + * @return int + */ + public function getTextRotation() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getTextRotation(); } - return $this->_textRotation; - } + return $this->_textRotation; + } - /** - * Set TextRotation - * - * @param int $pValue - * @throws Exception - * @return PHPExcel_Style_Alignment - */ - public function setTextRotation($pValue = 0) { + /** + * Set TextRotation + * + * @param int $pValue + * @throws Exception + * @return PHPExcel_Style_Alignment + */ + public function setTextRotation($pValue = 0) { // Excel2007 value 255 => PHPExcel value -165 - if ($pValue == 255) { - $pValue = -165; - } + if ($pValue == 255) { + $pValue = -165; + } // Set rotation - if ( ($pValue >= -90 && $pValue <= 90) || $pValue == -165 ) { + if ( ($pValue >= -90 && $pValue <= 90) || $pValue == -165 ) { if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('rotation' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); } else { $this->_textRotation = $pValue; } - } else { - throw new Exception("Text rotation should be a value between -90 and 90."); - } + } else { + throw new Exception("Text rotation should be a value between -90 and 90."); + } - return $this; - } + return $this; + } - /** - * Get Wrap Text - * - * @return boolean - */ - public function getWrapText() { + /** + * Get Wrap Text + * + * @return boolean + */ + public function getWrapText() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getWrapText(); } - return $this->_wrapText; - } + return $this->_wrapText; + } - /** - * Set Wrap Text - * - * @param boolean $pValue - * @return PHPExcel_Style_Alignment - */ - public function setWrapText($pValue = false) { - if ($pValue == '') { - $pValue = false; - } + /** + * Set Wrap Text + * + * @param boolean $pValue + * @return PHPExcel_Style_Alignment + */ + public function setWrapText($pValue = false) { + if ($pValue == '') { + $pValue = false; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('wrap' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -387,30 +379,30 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable $this->_wrapText = $pValue; } return $this; - } + } - /** - * Get Shrink to fit - * - * @return boolean - */ - public function getShrinkToFit() { + /** + * Get Shrink to fit + * + * @return boolean + */ + public function getShrinkToFit() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getShrinkToFit(); } - return $this->_shrinkToFit; - } + return $this->_shrinkToFit; + } - /** - * Set Shrink to fit - * - * @param boolean $pValue - * @return PHPExcel_Style_Alignment - */ - public function setShrinkToFit($pValue = false) { - if ($pValue == '') { - $pValue = false; - } + /** + * Set Shrink to fit + * + * @param boolean $pValue + * @return PHPExcel_Style_Alignment + */ + public function setShrinkToFit($pValue = false) { + if ($pValue == '') { + $pValue = false; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('shrinkToFit' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -418,27 +410,27 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable $this->_shrinkToFit = $pValue; } return $this; - } + } - /** - * Get indent - * - * @return int - */ - public function getIndent() { + /** + * Get indent + * + * @return int + */ + public function getIndent() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getIndent(); } - return $this->_indent; - } + return $this->_indent; + } - /** - * Set indent - * - * @param int $pValue - * @return PHPExcel_Style_Alignment - */ - public function setIndent($pValue = 0) { + /** + * Set indent + * + * @param int $pValue + * @return PHPExcel_Style_Alignment + */ + public function setIndent($pValue = 0) { if ($pValue > 0) { if ($this->getHorizontal() != self::HORIZONTAL_GENERAL && $this->getHorizontal() != self::HORIZONTAL_LEFT && $this->getHorizontal() != self::HORIZONTAL_RIGHT) { $pValue = 0; // indent not supported @@ -451,7 +443,7 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable $this->_indent = $pValue; } return $this; - } + } /** * Get hash code @@ -462,16 +454,16 @@ class PHPExcel_Style_Alignment implements PHPExcel_IComparable if ($this->_isSupervisor) { return $this->getSharedComponent()->getHashCode(); } - return md5( - $this->_horizontal - . $this->_vertical - . $this->_textRotation - . ($this->_wrapText ? 't' : 'f') - . ($this->_shrinkToFit ? 't' : 'f') + return md5( + $this->_horizontal + . $this->_vertical + . $this->_textRotation + . ($this->_wrapText ? 't' : 'f') + . ($this->_shrinkToFit ? 't' : 'f') . $this->_indent - . __CLASS__ - ); - } + . __CLASS__ + ); + } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. diff --git a/libraries/PHPExcel/PHPExcel/Style/Border.php b/libraries/PHPExcel/PHPExcel/Style/Border.php index 166ccb216..c20de948a 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Border.php +++ b/libraries/PHPExcel/PHPExcel/Style/Border.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Style_Border * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Border implements PHPExcel_IComparable { @@ -56,7 +56,7 @@ class PHPExcel_Style_Border implements PHPExcel_IComparable * * @var string */ - private $_borderStyle; + private $_borderStyle = PHPExcel_Style_Border::BORDER_NONE; /** * Border color @@ -86,23 +86,22 @@ class PHPExcel_Style_Border implements PHPExcel_IComparable */ private $_parentPropertyName; - /** - * Create a new PHPExcel_Style_Border - */ - public function __construct($isSupervisor = false) - { - // Supervisor? + /** + * Create a new PHPExcel_Style_Border + */ + public function __construct($isSupervisor = false) + { + // Supervisor? $this->_isSupervisor = $isSupervisor; - // Initialise values - $this->_borderStyle = PHPExcel_Style_Border::BORDER_NONE; + // Initialise values $this->_color = new PHPExcel_Style_Color(PHPExcel_Style_Color::COLOR_BLACK, $isSupervisor); // bind parent if we are a supervisor if ($isSupervisor) { $this->_color->bindParent($this, '_color'); } - } + } /** * Bind parent. Only used for supervisor @@ -253,24 +252,24 @@ class PHPExcel_Style_Border implements PHPExcel_IComparable return $this->_parent->getStyleArray(array($key => $array)); } - /** - * Apply styles from array - * - * - * $objPHPExcel->getActiveSheet()->getStyle('B2')->getBorders()->getTop()->applyFromArray( - * array( - * 'style' => PHPExcel_Style_Border::BORDER_DASHDOT, - * 'color' => array( - * 'rgb' => '808080' - * ) - * ) - * ); - * - * - * @param array $pStyles Array containing style information - * @throws Exception - * @return PHPExcel_Style_Border - */ + /** + * Apply styles from array + * + * + * $objPHPExcel->getActiveSheet()->getStyle('B2')->getBorders()->getTop()->applyFromArray( + * array( + * 'style' => PHPExcel_Style_Border::BORDER_DASHDOT, + * 'color' => array( + * 'rgb' => '808080' + * ) + * ) + * ); + * + * + * @param array $pStyles Array containing style information + * @throws Exception + * @return PHPExcel_Style_Border + */ public function applyFromArray($pStyles = null) { if (is_array($pStyles)) { if ($this->_isSupervisor) { @@ -289,29 +288,29 @@ class PHPExcel_Style_Border implements PHPExcel_IComparable return $this; } - /** - * Get Border style - * - * @return string - */ - public function getBorderStyle() { + /** + * Get Border style + * + * @return string + */ + public function getBorderStyle() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getBorderStyle(); } - return $this->_borderStyle; - } + return $this->_borderStyle; + } - /** - * Set Border style - * - * @param string $pValue - * @return PHPExcel_Style_Border - */ - public function setBorderStyle($pValue = PHPExcel_Style_Border::BORDER_NONE) { + /** + * Set Border style + * + * @param string $pValue + * @return PHPExcel_Style_Border + */ + public function setBorderStyle($pValue = PHPExcel_Style_Border::BORDER_NONE) { - if ($pValue == '') { - $pValue = PHPExcel_Style_Border::BORDER_NONE; - } + if ($pValue == '') { + $pValue = PHPExcel_Style_Border::BORDER_NONE; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('style' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -319,25 +318,25 @@ class PHPExcel_Style_Border implements PHPExcel_IComparable $this->_borderStyle = $pValue; } return $this; - } + } - /** - * Get Border Color - * - * @return PHPExcel_Style_Color - */ - public function getColor() { - return $this->_color; - } + /** + * Get Border Color + * + * @return PHPExcel_Style_Color + */ + public function getColor() { + return $this->_color; + } - /** - * Set Border Color - * - * @param PHPExcel_Style_Color $pValue - * @throws Exception - * @return PHPExcel_Style_Border - */ - public function setColor(PHPExcel_Style_Color $pValue = null) { + /** + * Set Border Color + * + * @param PHPExcel_Style_Color $pValue + * @throws Exception + * @return PHPExcel_Style_Border + */ + public function setColor(PHPExcel_Style_Color $pValue = null) { // make sure parameter is a real color and not a supervisor $color = $pValue->getIsSupervisor() ? $pValue->getSharedComponent() : $pValue; @@ -348,7 +347,7 @@ class PHPExcel_Style_Border implements PHPExcel_IComparable $this->_color = $color; } return $this; - } + } /** * Get hash code @@ -359,12 +358,12 @@ class PHPExcel_Style_Border implements PHPExcel_IComparable if ($this->_isSupervisor) { return $this->getSharedComponent()->getHashCode(); } - return md5( - $this->_borderStyle - . $this->_color->getHashCode() - . __CLASS__ - ); - } + return md5( + $this->_borderStyle + . $this->_color->getHashCode() + . __CLASS__ + ); + } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. diff --git a/libraries/PHPExcel/PHPExcel/Style/Borders.php b/libraries/PHPExcel/PHPExcel/Style/Borders.php index dc32c50ee..46c51b6d0 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Borders.php +++ b/libraries/PHPExcel/PHPExcel/Style/Borders.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Borders implements PHPExcel_IComparable { @@ -315,6 +315,12 @@ class PHPExcel_Style_Borders implements PHPExcel_IComparable if (array_key_exists('diagonaldirection', $pStyles)) { $this->setDiagonalDirection($pStyles['diagonaldirection']); } + if (array_key_exists('allborders', $pStyles)) { + $this->getLeft()->applyFromArray($pStyles['allborders']); + $this->getRight()->applyFromArray($pStyles['allborders']); + $this->getTop()->applyFromArray($pStyles['allborders']); + $this->getBottom()->applyFromArray($pStyles['allborders']); + } } } else { throw new Exception("Invalid style array passed."); diff --git a/libraries/PHPExcel/PHPExcel/Style/Color.php b/libraries/PHPExcel/PHPExcel/Style/Color.php index 9734d629c..b36e69c0e 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Color.php +++ b/libraries/PHPExcel/PHPExcel/Style/Color.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Color implements PHPExcel_IComparable { @@ -291,13 +291,78 @@ class PHPExcel_Style_Color implements PHPExcel_IComparable return $this; } - /** + private static function _getColourComponent($RGB,$offset,$hex=true) { + $colour = substr($RGB,$offset,2); + if (!$hex) + $colour = hexdec($colour); + return $colour; + } + + public static function getRed($RGB,$hex=true) { + if (strlen($RGB) == 8) { + return self::_getColourComponent($RGB,2,$hex); + } elseif (strlen($RGB) == 6) { + return self::_getColourComponent($RGB,0,$hex); + } + } + + public static function getGreen($RGB,$hex=true) { + if (strlen($RGB) == 8) { + return self::_getColourComponent($RGB,4,$hex); + } elseif (strlen($RGB) == 6) { + return self::_getColourComponent($RGB,2,$hex); + } + } + + public static function getBlue($RGB,$hex=true) { + if (strlen($RGB) == 8) { + return self::_getColourComponent($RGB,6,$hex); + } elseif (strlen($RGB) == 6) { + return self::_getColourComponent($RGB,4,$hex); + } + } + + /** + * Adjust the brightness of a color + * + * @param string $hex The colour as an RGB value (e.g. FF00CCCC or CCDDEE + * @param float $adjustPercentage The percentage by which to adjust the colour as a float from -1 to 1 + * @return string The adjusted colour as an RGB value (e.g. FF00CCCC or CCDDEE + */ + public static function changeBrightness($hex, $adjustPercentage) { + $red = self::getRed($hex,false); + $green = self::getGreen($hex,false); + $blue = self::getBlue($hex,false); + if ($adjustPercentage > 0) { + $red += (255 - $red) * $adjustPercentage; + $green += (255 - $green) * $adjustPercentage; + $blue += (255 - $blue) * $adjustPercentage; + } else { + $red += $red * $adjustPercentage; + $green += $green * $adjustPercentage; + $blue += $blue * $adjustPercentage; + } + + if ($red < 0) $red = 0; + elseif ($red > 255) $red = 255; + if ($green < 0) $green = 0; + elseif ($green > 255) $green = 255; + if ($blue < 0) $blue = 0; + elseif ($blue > 255) $blue = 255; + + return strtoupper( str_pad(dechex($red), 2, '0', 0) . + str_pad(dechex($green), 2, '0', 0) . + str_pad(dechex($blue), 2, '0', 0) + ); + } + + /** * Get indexed color * * @param int $pIndex * @return PHPExcel_Style_Color */ - public static function indexedColor($pIndex) { + public static function indexedColor($pIndex, $background=false) { // Clean parameter $pIndex = intval($pIndex); @@ -374,7 +439,10 @@ class PHPExcel_Style_Color implements PHPExcel_IComparable return new PHPExcel_Style_Color(self::$_indexedColors[$pIndex]); } - return new PHPExcel_Style_Color(); + if ($background) { + return new PHPExcel_Style_Color('FFFFFFFF'); + } + return new PHPExcel_Style_Color('FF000000'); } /** diff --git a/libraries/PHPExcel/PHPExcel/Style/Conditional.php b/libraries/PHPExcel/PHPExcel/Style/Conditional.php index 4602b5348..fbdb62368 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Conditional.php +++ b/libraries/PHPExcel/PHPExcel/Style/Conditional.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Conditional implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/Style/Fill.php b/libraries/PHPExcel/PHPExcel/Style/Fill.php index 1357e47ae..b9b1e63ad 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Fill.php +++ b/libraries/PHPExcel/PHPExcel/Style/Fill.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Style_Fill * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Fill implements PHPExcel_IComparable { @@ -63,14 +63,14 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable * * @var string */ - private $_fillType; + private $_fillType = PHPExcel_Style_Fill::FILL_NONE; /** * Rotation * * @var double */ - private $_rotation; + private $_rotation = 0; /** * Start color @@ -107,17 +107,15 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable */ private $_parent; - /** - * Create a new PHPExcel_Style_Fill - */ - public function __construct($isSupervisor = false) - { - // Supervisor? + /** + * Create a new PHPExcel_Style_Fill + */ + public function __construct($isSupervisor = false) + { + // Supervisor? $this->_isSupervisor = $isSupervisor; - // Initialise values - $this->_fillType = PHPExcel_Style_Fill::FILL_NONE; - $this->_rotation = 0; + // Initialise values $this->_startColor = new PHPExcel_Style_Color(PHPExcel_Style_Color::COLOR_WHITE, $isSupervisor); $this->_endColor = new PHPExcel_Style_Color(PHPExcel_Style_Color::COLOR_BLACK, $isSupervisor); @@ -126,7 +124,7 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable $this->_startColor->bindParent($this, '_startColor'); $this->_endColor->bindParent($this, '_endColor'); } - } + } /** * Bind parent. Only used for supervisor @@ -204,28 +202,28 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable return array('fill' => $array); } - /** - * Apply styles from array - * - * - * $objPHPExcel->getActiveSheet()->getStyle('B2')->getFill()->applyFromArray( - * array( - * 'type' => PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR, - * 'rotation' => 0, - * 'startcolor' => array( - * 'rgb' => '000000' - * ), - * 'endcolor' => array( - * 'argb' => 'FFFFFFFF' - * ) - * ) - * ); - * - * - * @param array $pStyles Array containing style information - * @throws Exception - * @return PHPExcel_Style_Fill - */ + /** + * Apply styles from array + * + * + * $objPHPExcel->getActiveSheet()->getStyle('B2')->getFill()->applyFromArray( + * array( + * 'type' => PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR, + * 'rotation' => 0, + * 'startcolor' => array( + * 'rgb' => '000000' + * ), + * 'endcolor' => array( + * 'argb' => 'FFFFFFFF' + * ) + * ) + * ); + * + * + * @param array $pStyles Array containing style information + * @throws Exception + * @return PHPExcel_Style_Fill + */ public function applyFromArray($pStyles = null) { if (is_array($pStyles)) { if ($this->_isSupervisor) { @@ -253,25 +251,25 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable return $this; } - /** - * Get Fill Type - * - * @return string - */ - public function getFillType() { + /** + * Get Fill Type + * + * @return string + */ + public function getFillType() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getFillType(); } return $this->_fillType; - } + } - /** - * Set Fill Type - * - * @param string $pValue PHPExcel_Style_Fill fill type - * @return PHPExcel_Style_Fill - */ - public function setFillType($pValue = PHPExcel_Style_Fill::FILL_NONE) { + /** + * Set Fill Type + * + * @param string $pValue PHPExcel_Style_Fill fill type + * @return PHPExcel_Style_Fill + */ + public function setFillType($pValue = PHPExcel_Style_Fill::FILL_NONE) { if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('type' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -279,27 +277,27 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable $this->_fillType = $pValue; } return $this; - } + } - /** - * Get Rotation - * - * @return double - */ - public function getRotation() { + /** + * Get Rotation + * + * @return double + */ + public function getRotation() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getRotation(); } - return $this->_rotation; - } + return $this->_rotation; + } - /** - * Set Rotation - * - * @param double $pValue - * @return PHPExcel_Style_Fill - */ - public function setRotation($pValue = 0) { + /** + * Set Rotation + * + * @param double $pValue + * @return PHPExcel_Style_Fill + */ + public function setRotation($pValue = 0) { if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('rotation' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -307,25 +305,25 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable $this->_rotation = $pValue; } return $this; - } + } - /** - * Get Start Color - * - * @return PHPExcel_Style_Color - */ - public function getStartColor() { - return $this->_startColor; - } + /** + * Get Start Color + * + * @return PHPExcel_Style_Color + */ + public function getStartColor() { + return $this->_startColor; + } - /** - * Set Start Color - * - * @param PHPExcel_Style_Color $pValue - * @throws Exception - * @return PHPExcel_Style_Fill - */ - public function setStartColor(PHPExcel_Style_Color $pValue = null) { + /** + * Set Start Color + * + * @param PHPExcel_Style_Color $pValue + * @throws Exception + * @return PHPExcel_Style_Fill + */ + public function setStartColor(PHPExcel_Style_Color $pValue = null) { // make sure parameter is a real color and not a supervisor $color = $pValue->getIsSupervisor() ? $pValue->getSharedComponent() : $pValue; @@ -336,25 +334,25 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable $this->_startColor = $color; } return $this; - } + } - /** - * Get End Color - * - * @return PHPExcel_Style_Color - */ - public function getEndColor() { - return $this->_endColor; - } + /** + * Get End Color + * + * @return PHPExcel_Style_Color + */ + public function getEndColor() { + return $this->_endColor; + } - /** - * Set End Color - * - * @param PHPExcel_Style_Color $pValue - * @throws Exception - * @return PHPExcel_Style_Fill - */ - public function setEndColor(PHPExcel_Style_Color $pValue = null) { + /** + * Set End Color + * + * @param PHPExcel_Style_Color $pValue + * @throws Exception + * @return PHPExcel_Style_Fill + */ + public function setEndColor(PHPExcel_Style_Color $pValue = null) { // make sure parameter is a real color and not a supervisor $color = $pValue->getIsSupervisor() ? $pValue->getSharedComponent() : $pValue; @@ -365,7 +363,7 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable $this->_endColor = $color; } return $this; - } + } /** * Get hash code @@ -376,14 +374,14 @@ class PHPExcel_Style_Fill implements PHPExcel_IComparable if ($this->_isSupervisor) { return $this->getSharedComponent()->getHashCode(); } - return md5( - $this->getFillType() - . $this->getRotation() - . $this->getStartColor()->getHashCode() - . $this->getEndColor()->getHashCode() - . __CLASS__ - ); - } + return md5( + $this->getFillType() + . $this->getRotation() + . $this->getStartColor()->getHashCode() + . $this->getEndColor()->getHashCode() + . __CLASS__ + ); + } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. diff --git a/libraries/PHPExcel/PHPExcel/Style/Font.php b/libraries/PHPExcel/PHPExcel/Style/Font.php index b58dbf53b..869244402 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Font.php +++ b/libraries/PHPExcel/PHPExcel/Style/Font.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Style_Font * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Font implements PHPExcel_IComparable { @@ -43,53 +43,60 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable const UNDERLINE_SINGLEACCOUNTING = 'singleAccounting'; /** - * Name + * Font Name * * @var string */ - private $_name; + private $_name = 'Calibri'; + + /** + * Font Size + * + * @var float + */ + private $_size = 11; /** * Bold * * @var boolean */ - private $_bold; + private $_bold = false; /** * Italic * * @var boolean */ - private $_italic; + private $_italic = false; /** * Superscript * * @var boolean */ - private $_superScript; + private $_superScript = false; /** * Subscript * * @var boolean */ - private $_subScript; + private $_subScript = false; /** * Underline * * @var string */ - private $_underline; + private $_underline = PHPExcel_Style_Font::UNDERLINE_NONE; /** * Strikethrough * * @var boolean */ - private $_strikethrough; + private $_strikethrough = false; /** * Foreground color @@ -120,29 +127,21 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable private $_parent; /** - * Create a new PHPExcel_Style_Font - */ - public function __construct($isSupervisor = false) - { - // Supervisor? + * Create a new PHPExcel_Style_Font + */ + public function __construct($isSupervisor = false) + { + // Supervisor? $this->_isSupervisor = $isSupervisor; - // Initialise values - $this->_name = 'Calibri'; - $this->_size = 11; - $this->_bold = false; - $this->_italic = false; - $this->_superScript = false; - $this->_subScript = false; - $this->_underline = PHPExcel_Style_Font::UNDERLINE_NONE; - $this->_strikethrough = false; + // Initialise values $this->_color = new PHPExcel_Style_Color(PHPExcel_Style_Color::COLOR_BLACK, $isSupervisor); // bind parent if we are a supervisor if ($isSupervisor) { $this->_color->bindParent($this, '_color'); } - } + } /** * Bind parent. Only used for supervisor @@ -219,28 +218,28 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable return array('font' => $array); } - /** - * Apply styles from array - * - * - * $objPHPExcel->getActiveSheet()->getStyle('B2')->getFont()->applyFromArray( - * array( - * 'name' => 'Arial', - * 'bold' => true, - * 'italic' => false, - * 'underline' => PHPExcel_Style_Font::UNDERLINE_DOUBLE, - * 'strike' => false, - * 'color' => array( - * 'rgb' => '808080' - * ) - * ) - * ); - * - * - * @param array $pStyles Array containing style information - * @throws Exception - * @return PHPExcel_Style_Font - */ + /** + * Apply styles from array + * + * + * $objPHPExcel->getActiveSheet()->getStyle('B2')->getFont()->applyFromArray( + * array( + * 'name' => 'Arial', + * 'bold' => true, + * 'italic' => false, + * 'underline' => PHPExcel_Style_Font::UNDERLINE_DOUBLE, + * 'strike' => false, + * 'color' => array( + * 'rgb' => '808080' + * ) + * ) + * ); + * + * + * @param array $pStyles Array containing style information + * @throws Exception + * @return PHPExcel_Style_Font + */ public function applyFromArray($pStyles = null) { if (is_array($pStyles)) { if ($this->_isSupervisor) { @@ -280,28 +279,28 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable return $this; } - /** - * Get Name - * - * @return string - */ - public function getName() { + /** + * Get Name + * + * @return string + */ + public function getName() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getName(); } - return $this->_name; - } + return $this->_name; + } - /** - * Set Name - * - * @param string $pValue - * @return PHPExcel_Style_Font - */ - public function setName($pValue = 'Calibri') { - if ($pValue == '') { - $pValue = 'Calibri'; - } + /** + * Set Name + * + * @param string $pValue + * @return PHPExcel_Style_Font + */ + public function setName($pValue = 'Calibri') { + if ($pValue == '') { + $pValue = 'Calibri'; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('name' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -309,30 +308,30 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_name = $pValue; } return $this; - } + } - /** - * Get Size - * - * @return double - */ - public function getSize() { + /** + * Get Size + * + * @return double + */ + public function getSize() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getSize(); } - return $this->_size; - } + return $this->_size; + } - /** - * Set Size - * - * @param double $pValue - * @return PHPExcel_Style_Font - */ - public function setSize($pValue = 10) { - if ($pValue == '') { - $pValue = 10; - } + /** + * Set Size + * + * @param double $pValue + * @return PHPExcel_Style_Font + */ + public function setSize($pValue = 10) { + if ($pValue == '') { + $pValue = 10; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('size' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -340,30 +339,30 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_size = $pValue; } return $this; - } + } - /** - * Get Bold - * - * @return boolean - */ - public function getBold() { + /** + * Get Bold + * + * @return boolean + */ + public function getBold() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getBold(); } - return $this->_bold; - } + return $this->_bold; + } - /** - * Set Bold - * - * @param boolean $pValue - * @return PHPExcel_Style_Font - */ - public function setBold($pValue = false) { - if ($pValue == '') { - $pValue = false; - } + /** + * Set Bold + * + * @param boolean $pValue + * @return PHPExcel_Style_Font + */ + public function setBold($pValue = false) { + if ($pValue == '') { + $pValue = false; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('bold' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -371,30 +370,30 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_bold = $pValue; } return $this; - } + } - /** - * Get Italic - * - * @return boolean - */ - public function getItalic() { + /** + * Get Italic + * + * @return boolean + */ + public function getItalic() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getItalic(); } - return $this->_italic; - } + return $this->_italic; + } - /** - * Set Italic - * - * @param boolean $pValue - * @return PHPExcel_Style_Font - */ - public function setItalic($pValue = false) { - if ($pValue == '') { - $pValue = false; - } + /** + * Set Italic + * + * @param boolean $pValue + * @return PHPExcel_Style_Font + */ + public function setItalic($pValue = false) { + if ($pValue == '') { + $pValue = false; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('italic' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -402,30 +401,30 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_italic = $pValue; } return $this; - } + } - /** - * Get SuperScript - * - * @return boolean - */ - public function getSuperScript() { + /** + * Get SuperScript + * + * @return boolean + */ + public function getSuperScript() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getSuperScript(); } - return $this->_superScript; - } + return $this->_superScript; + } - /** - * Set SuperScript - * - * @param boolean $pValue - * @return PHPExcel_Style_Font - */ - public function setSuperScript($pValue = false) { - if ($pValue == '') { - $pValue = false; - } + /** + * Set SuperScript + * + * @param boolean $pValue + * @return PHPExcel_Style_Font + */ + public function setSuperScript($pValue = false) { + if ($pValue == '') { + $pValue = false; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('superScript' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -434,30 +433,30 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_subScript = !$pValue; } return $this; - } + } - /** - * Get SubScript - * - * @return boolean - */ - public function getSubScript() { + /** + * Get SubScript + * + * @return boolean + */ + public function getSubScript() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getSubScript(); } - return $this->_subScript; - } + return $this->_subScript; + } - /** - * Set SubScript - * - * @param boolean $pValue - * @return PHPExcel_Style_Font - */ - public function setSubScript($pValue = false) { - if ($pValue == '') { - $pValue = false; - } + /** + * Set SubScript + * + * @param boolean $pValue + * @return PHPExcel_Style_Font + */ + public function setSubScript($pValue = false) { + if ($pValue == '') { + $pValue = false; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('subScript' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -466,30 +465,30 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_superScript = !$pValue; } return $this; - } + } - /** - * Get Underline - * - * @return string - */ - public function getUnderline() { + /** + * Get Underline + * + * @return string + */ + public function getUnderline() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getUnderline(); } - return $this->_underline; - } + return $this->_underline; + } - /** - * Set Underline - * - * @param string $pValue PHPExcel_Style_Font underline type - * @return PHPExcel_Style_Font - */ - public function setUnderline($pValue = PHPExcel_Style_Font::UNDERLINE_NONE) { - if ($pValue == '') { - $pValue = PHPExcel_Style_Font::UNDERLINE_NONE; - } + /** + * Set Underline + * + * @param string $pValue PHPExcel_Style_Font underline type + * @return PHPExcel_Style_Font + */ + public function setUnderline($pValue = PHPExcel_Style_Font::UNDERLINE_NONE) { + if ($pValue == '') { + $pValue = PHPExcel_Style_Font::UNDERLINE_NONE; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('underline' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -497,51 +496,51 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_underline = $pValue; } return $this; - } + } - /** - * Get Striketrough - * - * @deprecated Use getStrikethrough() instead. - * @return boolean - */ - public function getStriketrough() { - return $this->getStrikethrough(); - } + /** + * Get Striketrough + * + * @deprecated Use getStrikethrough() instead. + * @return boolean + */ + public function getStriketrough() { + return $this->getStrikethrough(); + } - /** - * Set Striketrough - * - * @deprecated Use setStrikethrough() instead. - * @param boolean $pValue - * @return PHPExcel_Style_Font - */ - public function setStriketrough($pValue = false) { - return $this->setStrikethrough($pValue); - } + /** + * Set Striketrough + * + * @deprecated Use setStrikethrough() instead. + * @param boolean $pValue + * @return PHPExcel_Style_Font + */ + public function setStriketrough($pValue = false) { + return $this->setStrikethrough($pValue); + } - /** - * Get Strikethrough - * - * @return boolean - */ - public function getStrikethrough() { + /** + * Get Strikethrough + * + * @return boolean + */ + public function getStrikethrough() { if ($this->_isSupervisor) { return $this->getSharedComponent()->getStrikethrough(); } - return $this->_strikethrough; - } + return $this->_strikethrough; + } - /** - * Set Strikethrough - * - * @param boolean $pValue - * @return PHPExcel_Style_Font - */ - public function setStrikethrough($pValue = false) { - if ($pValue == '') { - $pValue = false; - } + /** + * Set Strikethrough + * + * @param boolean $pValue + * @return PHPExcel_Style_Font + */ + public function setStrikethrough($pValue = false) { + if ($pValue == '') { + $pValue = false; + } if ($this->_isSupervisor) { $styleArray = $this->getStyleArray(array('strike' => $pValue)); $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); @@ -549,25 +548,25 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_strikethrough = $pValue; } return $this; - } + } - /** - * Get Color - * - * @return PHPExcel_Style_Color - */ - public function getColor() { - return $this->_color; - } + /** + * Get Color + * + * @return PHPExcel_Style_Color + */ + public function getColor() { + return $this->_color; + } - /** - * Set Color - * - * @param PHPExcel_Style_Color $pValue - * @throws Exception - * @return PHPExcel_Style_Font - */ - public function setColor(PHPExcel_Style_Color $pValue = null) { + /** + * Set Color + * + * @param PHPExcel_Style_Color $pValue + * @throws Exception + * @return PHPExcel_Style_Font + */ + public function setColor(PHPExcel_Style_Color $pValue = null) { // make sure parameter is a real color and not a supervisor $color = $pValue->getIsSupervisor() ? $pValue->getSharedComponent() : $pValue; @@ -578,7 +577,7 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable $this->_color = $color; } return $this; - } + } /** * Get hash code @@ -589,19 +588,19 @@ class PHPExcel_Style_Font implements PHPExcel_IComparable if ($this->_isSupervisor) { return $this->getSharedComponent()->getHashCode(); } - return md5( - $this->_name - . $this->_size - . ($this->_bold ? 't' : 'f') - . ($this->_italic ? 't' : 'f') + return md5( + $this->_name + . $this->_size + . ($this->_bold ? 't' : 'f') + . ($this->_italic ? 't' : 'f') . ($this->_superScript ? 't' : 'f') . ($this->_subScript ? 't' : 'f') - . $this->_underline - . ($this->_strikethrough ? 't' : 'f') - . $this->_color->getHashCode() - . __CLASS__ - ); - } + . $this->_underline + . ($this->_strikethrough ? 't' : 'f') + . $this->_color->getHashCode() + . __CLASS__ + ); + } /** * Implement PHP __clone to create a deep clone, not just a shallow copy. diff --git a/libraries/PHPExcel/PHPExcel/Style/NumberFormat.php b/libraries/PHPExcel/PHPExcel/Style/NumberFormat.php index 0f0dcdcdd..73fe39622 100644 --- a/libraries/PHPExcel/PHPExcel/Style/NumberFormat.php +++ b/libraries/PHPExcel/PHPExcel/Style/NumberFormat.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Style_NumberFormat * * @category PHPExcel - * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Style + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable { @@ -94,14 +94,14 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable * * @var string */ - private $_formatCode; + private $_formatCode = PHPExcel_Style_NumberFormat::FORMAT_GENERAL; /** * Built-in format Code * * @var string */ - private $_builtInFormatCode; + private $_builtInFormatCode = 0; /** * Parent Borders @@ -131,10 +131,6 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable { // Supervisor? $this->_isSupervisor = $isSupervisor; - - // Initialise values - $this->_formatCode = PHPExcel_Style_NumberFormat::FORMAT_GENERAL; - $this->_builtInFormatCode = 0; } /** @@ -217,9 +213,9 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable * * * $objPHPExcel->getActiveSheet()->getStyle('B2')->getNumberFormat()->applyFromArray( - * array( - * 'code' => PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE - * ) + * array( + * 'code' => PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE + * ) * ); * * @@ -323,7 +319,7 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable self::$_builtInFormats = array(); // General - self::$_builtInFormats[0] = 'General'; + self::$_builtInFormats[0] = PHPExcel_Style_NumberFormat::FORMAT_GENERAL; self::$_builtInFormats[1] = '0'; self::$_builtInFormats[2] = '0.00'; self::$_builtInFormats[3] = '#,##0'; @@ -393,7 +389,7 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable self::fillBuiltInFormatCodes(); // Lookup format code - if (array_key_exists($pIndex, self::$_builtInFormats)) { + if (isset(self::$_builtInFormats[$pIndex])) { return self::$_builtInFormats[$pIndex]; } @@ -412,7 +408,7 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable self::fillBuiltInFormatCodes(); // Lookup format code - if (array_key_exists($formatCode, self::$_flippedBuiltInFormats)) { + if (isset(self::$_flippedBuiltInFormats[$formatCode])) { return self::$_flippedBuiltInFormats[$formatCode]; } @@ -497,8 +493,8 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable /** * Convert a value in a pre-defined format to a PHP string * - * @param mixed $value Value to format - * @param string $format Format code + * @param mixed $value Value to format + * @param string $format Format code * @param array $callBack Callback function for additional formatting of string * @return string Formatted string */ @@ -509,7 +505,7 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable // For 'General' format code, we just pass the value although this is not entirely the way Excel does it, // it seems to round numbers to a total of 10 digits. - if ($format === 'General') { + if (($format === PHPExcel_Style_NumberFormat::FORMAT_GENERAL) || ($format === PHPExcel_Style_NumberFormat::FORMAT_TEXT)) { return $value; } @@ -609,8 +605,8 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable // Some non-number characters are escaped with \, which we don't need $format = preg_replace("/\\\\/", '', $format); - // Some non-number strings are quoted, so we'll get rid of the quotes - $format = preg_replace('/"/', '', $format); + // Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols + $format = str_replace(array('"','*'), '', $format); // Find out if we need thousands separator // This is indicated by a comma enclosed by a digit placeholder: @@ -623,7 +619,7 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable // Scale thousands, millions,... // This is indicated by a number of commas after a digit placeholder: - // #, or 0.0,, + // #, or 0.0,, $scale = 1; // same as no scale $matches = array(); if (preg_match('/(#|0)(,+)/', $format, $matches)) { @@ -644,12 +640,12 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable $decimalLength = strlen($decimalPart); $decimalDivisor = pow(10,$decimalLength); - $GCD = PHPExcel_Calculation_Functions::GCD($decimalPart,$decimalDivisor); + $GCD = PHPExcel_Calculation_MathTrig::GCD($decimalPart,$decimalDivisor); $adjustedDecimalPart = $decimalPart/$GCD; $adjustedDecimalDivisor = $decimalDivisor/$GCD; - if ((strpos($format,'0') !== false) || (substr($format,0,3) == '? ?')) { + if ((strpos($format,'0') !== false) || (strpos($format,'#') !== false) || (substr($format,0,3) == '? ?')) { if ($integerPart == 0) { $integerPart = ''; } $value = "$sign$integerPart $adjustedDecimalPart/$adjustedDecimalDivisor"; } else { @@ -667,9 +663,10 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable // Strip # $format = preg_replace('/\\#/', '', $format); + $n = "/\[[^\]]+\]/"; + $m = preg_replace($n, '', $format); $number_regex = "/(0+)(\.?)(0*)/"; - $matches = array(); - if (preg_match($number_regex, $format, $matches)) { + if (preg_match($number_regex, $m, $matches)) { $left = $matches[1]; $dec = $matches[2]; $right = $matches[3]; @@ -679,12 +676,11 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable if ($useThousands) { $value = number_format( - $value - , strlen($right) - , PHPExcel_Shared_String::getDecimalSeparator() - , PHPExcel_Shared_String::getThousandsSeparator() - ); - + $value + , strlen($right) + , PHPExcel_Shared_String::getDecimalSeparator() + , PHPExcel_Shared_String::getThousandsSeparator() + ); } else { $sprintf_pattern = "%0$minWidth." . strlen($right) . "f"; $value = sprintf($sprintf_pattern, $value); @@ -693,6 +689,16 @@ class PHPExcel_Style_NumberFormat implements PHPExcel_IComparable $value = preg_replace($number_regex, $value, $format); } } + if (preg_match('/\[\$(.*)\]/u', $format, $m)) { + // Currency or Accounting + $currencyFormat = $m[0]; + $currencyCode = $m[1]; + list($currencyCode) = explode('-',$currencyCode); + if ($currencyCode == '') { + $currencyCode = PHPExcel_Shared_String::getCurrencyCode(); + } + $value = preg_replace('/\[\$([^\]]*)\]/u',$currencyCode,$value); + } } } diff --git a/libraries/PHPExcel/PHPExcel/Style/Protection.php b/libraries/PHPExcel/PHPExcel/Style/Protection.php index 29832dabd..84201a2f6 100644 --- a/libraries/PHPExcel/PHPExcel/Style/Protection.php +++ b/libraries/PHPExcel/PHPExcel/Style/Protection.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,7 +20,7 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL * @version 1.4.5, 2007-08-23 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Style - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Style_Protection implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet.php b/libraries/PHPExcel/PHPExcel/Worksheet.php index fb7cc0a30..a6d7054c1 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Worksheet + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Worksheet * * @category PHPExcel - * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Worksheet + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet implements PHPExcel_IComparable { @@ -41,8 +41,8 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable const BREAK_COLUMN = 2; /* Sheet state */ - const SHEETSTATE_VISIBLE = 'visible'; - const SHEETSTATE_HIDDEN = 'hidden'; + const SHEETSTATE_VISIBLE = 'visible'; + const SHEETSTATE_HIDDEN = 'hidden'; const SHEETSTATE_VERYHIDDEN = 'veryHidden'; /** @@ -304,11 +304,25 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable */ private $_tabColor; + /** + * Dirty flag + * + * @var boolean + */ + private $_dirty = true; + + /** + * Hash + * + * @var string + */ + private $_hash = null; + /** * Create a new worksheet * - * @param PHPExcel $pParent - * @param string $pTitle + * @param PHPExcel $pParent + * @param string $pTitle */ public function __construct(PHPExcel $pParent = null, $pTitle = 'Worksheet') { @@ -320,36 +334,28 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_cellCollection = PHPExcel_CachedObjectStorageFactory::getInstance($this); // Set page setup - $this->_pageSetup = new PHPExcel_Worksheet_PageSetup(); + $this->_pageSetup = new PHPExcel_Worksheet_PageSetup(); // Set page margins - $this->_pageMargins = new PHPExcel_Worksheet_PageMargins(); + $this->_pageMargins = new PHPExcel_Worksheet_PageMargins(); // Set page header/footer - $this->_headerFooter = new PHPExcel_Worksheet_HeaderFooter(); + $this->_headerFooter = new PHPExcel_Worksheet_HeaderFooter(); // Set sheet view - $this->_sheetView = new PHPExcel_Worksheet_SheetView(); + $this->_sheetView = new PHPExcel_Worksheet_SheetView(); - // Drawing collection - $this->_drawingCollection = new ArrayObject(); + // Drawing collection + $this->_drawingCollection = new ArrayObject(); - // Protection - $this->_protection = new PHPExcel_Worksheet_Protection(); + // Protection + $this->_protection = new PHPExcel_Worksheet_Protection(); - // Gridlines - $this->_showGridlines = true; - $this->_printGridlines = false; + // Default row dimension + $this->_defaultRowDimension = new PHPExcel_Worksheet_RowDimension(null); - // Outline summary - $this->_showSummaryBelow = true; - $this->_showSummaryRight = true; - - // Default row dimension - $this->_defaultRowDimension = new PHPExcel_Worksheet_RowDimension(null); - - // Default column dimension - $this->_defaultColumnDimension = new PHPExcel_Worksheet_ColumnDimension(null); + // Default column dimension + $this->_defaultColumnDimension = new PHPExcel_Worksheet_ColumnDimension(null); } @@ -430,7 +436,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable { if (!is_null($this->_cellCollection)) { return $this->_cellCollection->getSortedCellList(); - } + } return array(); } @@ -522,16 +528,16 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return $this; } - /** - * Calculate worksheet dimension - * - * @return string String containing the dimension of this worksheet - */ - public function calculateWorksheetDimension() - { - // Return - return 'A1' . ':' . $this->getHighestColumn() . $this->getHighestRow(); - } + /** + * Calculate worksheet dimension + * + * @return string String containing the dimension of this worksheet + */ + public function calculateWorksheetDimension() + { + // Return + return 'A1' . ':' . $this->getHighestColumn() . $this->getHighestRow(); + } /** * Calculate widths for auto-size columns @@ -593,24 +599,24 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } return $this; - } + } - /** - * Get parent - * - * @return PHPExcel - */ - public function getParent() { - return $this->_parent; - } + /** + * Get parent + * + * @return PHPExcel + */ + public function getParent() { + return $this->_parent; + } - /** - * Re-bind parent - * - * @param PHPExcel $parent - * @return PHPExcel_Worksheet - */ - public function rebindParent(PHPExcel $parent) { + /** + * Re-bind parent + * + * @param PHPExcel $parent + * @return PHPExcel_Worksheet + */ + public function rebindParent(PHPExcel $parent) { $namedRanges = $this->_parent->getNamedRanges(); foreach ($namedRanges as $namedRange) { $parent->addNamedRange($namedRange); @@ -622,7 +628,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_parent = $parent; return $this; - } + } /** * Get title @@ -634,49 +640,60 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return $this->_title; } - /** - * Set title - * - * @param string $pValue String containing the dimension of this worksheet + /** + * Set title + * + * @param string $pValue String containing the dimension of this worksheet * @return PHPExcel_Worksheet - */ - public function setTitle($pValue = 'Worksheet') - { - // Is this a 'rename' or not? - if ($this->getTitle() == $pValue) { - return; - } + */ + public function setTitle($pValue = 'Worksheet') + { + // Is this a 'rename' or not? + if ($this->getTitle() == $pValue) { + return $this; + } // Syntax check self::_checkSheetTitle($pValue); - // Old title - $oldTitle = $this->getTitle(); + // Old title + $oldTitle = $this->getTitle(); // Is there already such sheet name? if ($this->getParent()->getSheetByName($pValue)) { // Use name, but append with lowest possible integer + if (PHPExcel_Shared_String::CountCharacters($pValue) > 29) { + $pValue = PHPExcel_Shared_String::Substring($pValue,0,29); + } $i = 1; while ($this->getParent()->getSheetByName($pValue . ' ' . $i)) { ++$i; + if ($i == 10) { + if (PHPExcel_Shared_String::CountCharacters($pValue) > 28) { + $pValue = PHPExcel_Shared_String::Substring($pValue,0,28); + } + } elseif ($i == 100) { + if (PHPExcel_Shared_String::CountCharacters($pValue) > 27) { + $pValue = PHPExcel_Shared_String::Substring($pValue,0,27); + } + } } $altTitle = $pValue . ' ' . $i; - $this->setTitle($altTitle); - - return; + return $this->setTitle($altTitle); } // Set title - $this->_title = $pValue; + $this->_title = $pValue; + $this->_dirty = true; - // New title - $newTitle = $this->getTitle(); - PHPExcel_ReferenceHelper::getInstance()->updateNamedFormulas($this->getParent(), $oldTitle, $newTitle); + // New title + $newTitle = $this->getTitle(); + PHPExcel_ReferenceHelper::getInstance()->updateNamedFormulas($this->getParent(), $oldTitle, $newTitle); - return $this; - } + return $this; + } /** * Get sheet state @@ -698,213 +715,215 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return $this; } - /** - * Get page setup - * - * @return PHPExcel_Worksheet_PageSetup - */ - public function getPageSetup() - { - return $this->_pageSetup; - } + /** + * Get page setup + * + * @return PHPExcel_Worksheet_PageSetup + */ + public function getPageSetup() + { + return $this->_pageSetup; + } - /** - * Set page setup - * - * @param PHPExcel_Worksheet_PageSetup $pValue - * @return PHPExcel_Worksheet - */ - public function setPageSetup(PHPExcel_Worksheet_PageSetup $pValue) - { - $this->_pageSetup = $pValue; - return $this; - } + /** + * Set page setup + * + * @param PHPExcel_Worksheet_PageSetup $pValue + * @return PHPExcel_Worksheet + */ + public function setPageSetup(PHPExcel_Worksheet_PageSetup $pValue) + { + $this->_pageSetup = $pValue; + return $this; + } - /** - * Get page margins - * - * @return PHPExcel_Worksheet_PageMargins - */ - public function getPageMargins() - { - return $this->_pageMargins; - } + /** + * Get page margins + * + * @return PHPExcel_Worksheet_PageMargins + */ + public function getPageMargins() + { + return $this->_pageMargins; + } - /** - * Set page margins - * - * @param PHPExcel_Worksheet_PageMargins $pValue - * @return PHPExcel_Worksheet - */ - public function setPageMargins(PHPExcel_Worksheet_PageMargins $pValue) - { - $this->_pageMargins = $pValue; - return $this; - } + /** + * Set page margins + * + * @param PHPExcel_Worksheet_PageMargins $pValue + * @return PHPExcel_Worksheet + */ + public function setPageMargins(PHPExcel_Worksheet_PageMargins $pValue) + { + $this->_pageMargins = $pValue; + return $this; + } - /** - * Get page header/footer - * - * @return PHPExcel_Worksheet_HeaderFooter - */ - public function getHeaderFooter() - { - return $this->_headerFooter; - } + /** + * Get page header/footer + * + * @return PHPExcel_Worksheet_HeaderFooter + */ + public function getHeaderFooter() + { + return $this->_headerFooter; + } - /** - * Set page header/footer - * - * @param PHPExcel_Worksheet_HeaderFooter $pValue - * @return PHPExcel_Worksheet - */ - public function setHeaderFooter(PHPExcel_Worksheet_HeaderFooter $pValue) - { - $this->_headerFooter = $pValue; - return $this; - } + /** + * Set page header/footer + * + * @param PHPExcel_Worksheet_HeaderFooter $pValue + * @return PHPExcel_Worksheet + */ + public function setHeaderFooter(PHPExcel_Worksheet_HeaderFooter $pValue) + { + $this->_headerFooter = $pValue; + return $this; + } - /** - * Get sheet view - * - * @return PHPExcel_Worksheet_HeaderFooter - */ - public function getSheetView() - { - return $this->_sheetView; - } + /** + * Get sheet view + * + * @return PHPExcel_Worksheet_HeaderFooter + */ + public function getSheetView() + { + return $this->_sheetView; + } - /** - * Set sheet view - * - * @param PHPExcel_Worksheet_SheetView $pValue - * @return PHPExcel_Worksheet - */ - public function setSheetView(PHPExcel_Worksheet_SheetView $pValue) - { - $this->_sheetView = $pValue; - return $this; - } + /** + * Set sheet view + * + * @param PHPExcel_Worksheet_SheetView $pValue + * @return PHPExcel_Worksheet + */ + public function setSheetView(PHPExcel_Worksheet_SheetView $pValue) + { + $this->_sheetView = $pValue; + return $this; + } - /** - * Get Protection - * - * @return PHPExcel_Worksheet_Protection - */ - public function getProtection() - { - return $this->_protection; - } + /** + * Get Protection + * + * @return PHPExcel_Worksheet_Protection + */ + public function getProtection() + { + return $this->_protection; + } - /** - * Set Protection - * - * @param PHPExcel_Worksheet_Protection $pValue - * @return PHPExcel_Worksheet - */ - public function setProtection(PHPExcel_Worksheet_Protection $pValue) - { - $this->_protection = $pValue; - return $this; - } + /** + * Set Protection + * + * @param PHPExcel_Worksheet_Protection $pValue + * @return PHPExcel_Worksheet + */ + public function setProtection(PHPExcel_Worksheet_Protection $pValue) + { + $this->_protection = $pValue; + $this->_dirty = true; - /** - * Get highest worksheet column - * - * @return string Highest column name - */ - public function getHighestColumn() - { + return $this; + } + + /** + * Get highest worksheet column + * + * @return string Highest column name + */ + public function getHighestColumn() + { return $this->_cachedHighestColumn; - } + } - /** - * Get highest worksheet row - * - * @return int Highest row number - */ - public function getHighestRow() - { + /** + * Get highest worksheet row + * + * @return int Highest row number + */ + public function getHighestRow() + { return $this->_cachedHighestRow; - } + } - /** - * Set a cell value - * - * @param string $pCoordinate Coordinate of the cell - * @param mixed $pValue Value of the cell - * @param bool $returnCell Return the worksheet (false, default) or the cell (true) - * @return PHPExcel_Worksheet|PHPExcel_Cell Depending on the last parameter being specified - */ - public function setCellValue($pCoordinate = 'A1', $pValue = null, $returnCell = false) - { + /** + * Set a cell value + * + * @param string $pCoordinate Coordinate of the cell + * @param mixed $pValue Value of the cell + * @param bool $returnCell Return the worksheet (false, default) or the cell (true) + * @return PHPExcel_Worksheet|PHPExcel_Cell Depending on the last parameter being specified + */ + public function setCellValue($pCoordinate = 'A1', $pValue = null, $returnCell = false) + { $cell = $this->getCell($pCoordinate); $cell->setValue($pValue); if ($returnCell) { return $cell; } - return $this; - } + return $this; + } - /** - * Set a cell value by using numeric cell coordinates - * - * @param string $pColumn Numeric column coordinate of the cell - * @param string $pRow Numeric row coordinate of the cell - * @param mixed $pValue Value of the cell - * @param bool $returnCell Return the worksheet (false, default) or the cell (true) - * @return PHPExcel_Worksheet|PHPExcel_Cell Depending on the last parameter being specified - */ - public function setCellValueByColumnAndRow($pColumn = 0, $pRow = 0, $pValue = null, $returnCell = false) - { - $cell = $this->getCell(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); + /** + * Set a cell value by using numeric cell coordinates + * + * @param string $pColumn Numeric column coordinate of the cell + * @param string $pRow Numeric row coordinate of the cell + * @param mixed $pValue Value of the cell + * @param bool $returnCell Return the worksheet (false, default) or the cell (true) + * @return PHPExcel_Worksheet|PHPExcel_Cell Depending on the last parameter being specified + */ + public function setCellValueByColumnAndRow($pColumn = 0, $pRow = 1, $pValue = null, $returnCell = false) + { + $cell = $this->getCell(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); $cell->setValue($pValue); if ($returnCell) { return $cell; } - return $this; - } + return $this; + } - /** - * Set a cell value - * - * @param string $pCoordinate Coordinate of the cell - * @param mixed $pValue Value of the cell - * @param string $pDataType Explicit data type - * @return PHPExcel_Worksheet - */ - public function setCellValueExplicit($pCoordinate = 'A1', $pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING) - { - // Set value - $this->getCell($pCoordinate)->setValueExplicit($pValue, $pDataType); - return $this; - } + /** + * Set a cell value + * + * @param string $pCoordinate Coordinate of the cell + * @param mixed $pValue Value of the cell + * @param string $pDataType Explicit data type + * @return PHPExcel_Worksheet + */ + public function setCellValueExplicit($pCoordinate = 'A1', $pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING) + { + // Set value + $this->getCell($pCoordinate)->setValueExplicit($pValue, $pDataType); + return $this; + } - /** - * Set a cell value by using numeric cell coordinates - * - * @param string $pColumn Numeric column coordinate of the cell - * @param string $pRow Numeric row coordinate of the cell - * @param mixed $pValue Value of the cell - * @param string $pDataType Explicit data type - * @return PHPExcel_Worksheet - */ - public function setCellValueExplicitByColumnAndRow($pColumn = 0, $pRow = 0, $pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING) - { - return $this->getCell(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow)->setValueExplicit($pValue, $pDataType); - } + /** + * Set a cell value by using numeric cell coordinates + * + * @param string $pColumn Numeric column coordinate of the cell + * @param string $pRow Numeric row coordinate of the cell + * @param mixed $pValue Value of the cell + * @param string $pDataType Explicit data type + * @return PHPExcel_Worksheet + */ + public function setCellValueExplicitByColumnAndRow($pColumn = 0, $pRow = 1, $pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING) + { + return $this->getCell(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow)->setValueExplicit($pValue, $pDataType); + } - /** - * Get cell at a specific coordinate - * - * @param string $pCoordinate Coordinate of the cell - * @throws Exception - * @return PHPExcel_Cell Cell that was found - */ - public function getCell($pCoordinate = 'A1') - { + /** + * Get cell at a specific coordinate + * + * @param string $pCoordinate Coordinate of the cell + * @throws Exception + * @return PHPExcel_Cell Cell that was found + */ + public function getCell($pCoordinate = 'A1') + { // Check cell collection if ($this->_cellCollection->isDataSet($pCoordinate)) { return $this->_cellCollection->getCacheData($pCoordinate); @@ -926,14 +945,14 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } } - // Uppercase coordinate - $pCoordinate = strtoupper($pCoordinate); + // Uppercase coordinate + $pCoordinate = strtoupper($pCoordinate); - if (strpos($pCoordinate,':') !== false || strpos($pCoordinate,',') !== false) { - throw new Exception('Cell coordinate can not be a range of cells.'); - } elseif (strpos($pCoordinate,'$') !== false) { - throw new Exception('Cell coordinate must not be absolute.'); - } else { + if (strpos($pCoordinate,':') !== false || strpos($pCoordinate,',') !== false) { + throw new Exception('Cell coordinate can not be a range of cells.'); + } elseif (strpos($pCoordinate,'$') !== false) { + throw new Exception('Cell coordinate must not be absolute.'); + } else { // Create new cell object // Coordinates @@ -945,11 +964,10 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < PHPExcel_Cell::columnIndexFromString($aCoordinates[0])) $this->_cachedHighestColumn = $aCoordinates[0]; - if ($this->_cachedHighestRow < $aCoordinates[1]) - $this->_cachedHighestRow = $aCoordinates[1]; + $this->_cachedHighestRow = max($this->_cachedHighestRow,$aCoordinates[1]); // Cell needs appropriate xfIndex - $rowDimensions = $this->getRowDimensions(); + $rowDimensions = $this->getRowDimensions(); $columnDimensions = $this->getColumnDimensions(); if ( isset($rowDimensions[$aCoordinates[1]]) && $rowDimensions[$aCoordinates[1]]->getXfIndex() !== null ) { @@ -964,18 +982,18 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } return $cell; - } - } + } + } - /** - * Get cell at a specific coordinate by using numeric cell coordinates - * - * @param string $pColumn Numeric column coordinate of the cell - * @param string $pRow Numeric row coordinate of the cell - * @return PHPExcel_Cell Cell that was found - */ - public function getCellByColumnAndRow($pColumn = 0, $pRow = 0) - { + /** + * Get cell at a specific coordinate by using numeric cell coordinates + * + * @param string $pColumn Numeric column coordinate of the cell + * @param string $pRow Numeric row coordinate of the cell + * @return PHPExcel_Cell Cell that was found + */ + public function getCellByColumnAndRow($pColumn = 0, $pRow = 1) + { $columnLetter = PHPExcel_Cell::stringFromColumnIndex($pColumn); $coordinate = $columnLetter . $pRow; @@ -986,25 +1004,24 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < $pColumn) $this->_cachedHighestColumn = $columnLetter; - if ($this->_cachedHighestRow < $pRow) - $this->_cachedHighestRow = $pRow; + $this->_cachedHighestRow = max($this->_cachedHighestRow,$pRow); return $cell; } return $this->_cellCollection->getCacheData($coordinate); - } + } - /** - * Cell at a specific coordinate exists? - * - * @param string $pCoordinate Coordinate of the cell - * @throws Exception - * @return boolean - */ - public function cellExists($pCoordinate = 'A1') - { - // Worksheet reference? + /** + * Cell at a specific coordinate exists? + * + * @param string $pCoordinate Coordinate of the cell + * @throws Exception + * @return boolean + */ + public function cellExists($pCoordinate = 'A1') + { + // Worksheet reference? if (strpos($pCoordinate, '!') !== false) { $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pCoordinate, true); return $this->getParent()->getSheetByName($worksheetReference[0])->cellExists($worksheetReference[1]); @@ -1026,120 +1043,119 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } } - // Uppercase coordinate - $pCoordinate = strtoupper($pCoordinate); + // Uppercase coordinate + $pCoordinate = strtoupper($pCoordinate); - if (strpos($pCoordinate,':') !== false || strpos($pCoordinate,',') !== false) { - throw new Exception('Cell coordinate can not be a range of cells.'); - } elseif (strpos($pCoordinate,'$') !== false) { - throw new Exception('Cell coordinate must not be absolute.'); - } else { - // Coordinates - $aCoordinates = PHPExcel_Cell::coordinateFromString($pCoordinate); + if (strpos($pCoordinate,':') !== false || strpos($pCoordinate,',') !== false) { + throw new Exception('Cell coordinate can not be a range of cells.'); + } elseif (strpos($pCoordinate,'$') !== false) { + throw new Exception('Cell coordinate must not be absolute.'); + } else { + // Coordinates + $aCoordinates = PHPExcel_Cell::coordinateFromString($pCoordinate); - // Cell exists? + // Cell exists? return $this->_cellCollection->isDataSet($pCoordinate); - } - } + } + } - /** - * Cell at a specific coordinate by using numeric cell coordinates exists? - * - * @param string $pColumn Numeric column coordinate of the cell - * @param string $pRow Numeric row coordinate of the cell - * @return boolean - */ - public function cellExistsByColumnAndRow($pColumn = 0, $pRow = 0) - { - return $this->cellExists(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); - } + /** + * Cell at a specific coordinate by using numeric cell coordinates exists? + * + * @param string $pColumn Numeric column coordinate of the cell + * @param string $pRow Numeric row coordinate of the cell + * @return boolean + */ + public function cellExistsByColumnAndRow($pColumn = 0, $pRow = 1) + { + return $this->cellExists(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); + } - /** - * Get row dimension at a specific row - * - * @param int $pRow Numeric index of the row - * @return PHPExcel_Worksheet_RowDimension - */ - public function getRowDimension($pRow = 0) - { - // Found - $found = null; + /** + * Get row dimension at a specific row + * + * @param int $pRow Numeric index of the row + * @return PHPExcel_Worksheet_RowDimension + */ + public function getRowDimension($pRow = 1) + { + // Found + $found = null; - // Get row dimension - if (!isset($this->_rowDimensions[$pRow])) { - $this->_rowDimensions[$pRow] = new PHPExcel_Worksheet_RowDimension($pRow); + // Get row dimension + if (!isset($this->_rowDimensions[$pRow])) { + $this->_rowDimensions[$pRow] = new PHPExcel_Worksheet_RowDimension($pRow); - if ($this->_cachedHighestRow < $pRow) - $this->_cachedHighestRow = $pRow; - } - return $this->_rowDimensions[$pRow]; - } + $this->_cachedHighestRow = max($this->_cachedHighestRow,$pRow); + } + return $this->_rowDimensions[$pRow]; + } - /** - * Get column dimension at a specific column - * - * @param string $pColumn String index of the column - * @return PHPExcel_Worksheet_ColumnDimension - */ - public function getColumnDimension($pColumn = 'A') - { - // Uppercase coordinate - $pColumn = strtoupper($pColumn); + /** + * Get column dimension at a specific column + * + * @param string $pColumn String index of the column + * @return PHPExcel_Worksheet_ColumnDimension + */ + public function getColumnDimension($pColumn = 'A') + { + // Uppercase coordinate + $pColumn = strtoupper($pColumn); - // Fetch dimensions - if (!isset($this->_columnDimensions[$pColumn])) { - $this->_columnDimensions[$pColumn] = new PHPExcel_Worksheet_ColumnDimension($pColumn); + // Fetch dimensions + if (!isset($this->_columnDimensions[$pColumn])) { + $this->_columnDimensions[$pColumn] = new PHPExcel_Worksheet_ColumnDimension($pColumn); if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < PHPExcel_Cell::columnIndexFromString($pColumn)) $this->_cachedHighestColumn = $pColumn; - } - return $this->_columnDimensions[$pColumn]; - } + } + return $this->_columnDimensions[$pColumn]; + } - /** - * Get column dimension at a specific column by using numeric cell coordinates - * - * @param string $pColumn Numeric column coordinate of the cell - * @param string $pRow Numeric row coordinate of the cell - * @return PHPExcel_Worksheet_ColumnDimension - */ - public function getColumnDimensionByColumn($pColumn = 0) - { - return $this->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($pColumn)); - } + /** + * Get column dimension at a specific column by using numeric cell coordinates + * + * @param string $pColumn Numeric column coordinate of the cell + * @param string $pRow Numeric row coordinate of the cell + * @return PHPExcel_Worksheet_ColumnDimension + */ + public function getColumnDimensionByColumn($pColumn = 0) + { + return $this->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($pColumn)); + } - /** - * Get styles - * - * @return PHPExcel_Style[] - */ - public function getStyles() - { - return $this->_styles; - } + /** + * Get styles + * + * @return PHPExcel_Style[] + */ + public function getStyles() + { + return $this->_styles; + } - /** - * Get default style of workbork. - * - * @deprecated - * @return PHPExcel_Style - * @throws Exception - */ - public function getDefaultStyle() - { - return $this->_parent->getDefaultStyle(); - } + /** + * Get default style of workbork. + * + * @deprecated + * @return PHPExcel_Style + * @throws Exception + */ + public function getDefaultStyle() + { + return $this->_parent->getDefaultStyle(); + } - /** - * Set default style - should only be used by PHPExcel_IReader implementations! - * - * @deprecated - * @param PHPExcel_Style $value - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setDefaultStyle(PHPExcel_Style $pValue) - { + /** + * Set default style - should only be used by PHPExcel_IReader implementations! + * + * @deprecated + * @param PHPExcel_Style $value + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setDefaultStyle(PHPExcel_Style $pValue) + { $this->_parent->getDefaultStyle()->applyFromArray(array( 'font' => array( 'name' => $pValue->getFont()->getName(), @@ -1147,17 +1163,17 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable ), )); return $this; - } + } - /** - * Get style for cell - * - * @param string $pCellCoordinate Cell coordinate to get style for - * @return PHPExcel_Style - * @throws Exception - */ - public function getStyle($pCellCoordinate = 'A1') - { + /** + * Get style for cell + * + * @param string $pCellCoordinate Cell coordinate to get style for + * @return PHPExcel_Style + * @throws Exception + */ + public function getStyle($pCellCoordinate = 'A1') + { // set this sheet as active $this->_parent->setActiveSheetIndex($this->_parent->getIndex($this)); @@ -1165,7 +1181,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->setSelectedCells($pCellCoordinate); return $this->_parent->getCellXfSupervisor(); - } + } /** * Get conditional styles for a cell @@ -1230,48 +1246,48 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return $this; } - /** - * Get style for cell by using numeric cell coordinates - * - * @param int $pColumn Numeric column coordinate of the cell - * @param int $pRow Numeric row coordinate of the cell - * @return PHPExcel_Style - */ - public function getStyleByColumnAndRow($pColumn = 0, $pRow = 0) - { - return $this->getStyle(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); - } + /** + * Get style for cell by using numeric cell coordinates + * + * @param int $pColumn Numeric column coordinate of the cell + * @param int $pRow Numeric row coordinate of the cell + * @return PHPExcel_Style + */ + public function getStyleByColumnAndRow($pColumn = 0, $pRow = 1) + { + return $this->getStyle(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); + } - /** - * Set shared cell style to a range of cells - * - * Please note that this will overwrite existing cell styles for cells in range! - * - * @deprecated - * @param PHPExcel_Style $pSharedCellStyle Cell style to share - * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setSharedStyle(PHPExcel_Style $pSharedCellStyle = null, $pRange = '') - { + /** + * Set shared cell style to a range of cells + * + * Please note that this will overwrite existing cell styles for cells in range! + * + * @deprecated + * @param PHPExcel_Style $pSharedCellStyle Cell style to share + * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setSharedStyle(PHPExcel_Style $pSharedCellStyle = null, $pRange = '') + { $this->duplicateStyle($pSharedCellStyle, $pRange); return $this; - } + } - /** - * Duplicate cell style to a range of cells - * - * Please note that this will overwrite existing cell styles for cells in range! - * - * @param PHPExcel_Style $pCellStyle Cell style to duplicate - * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function duplicateStyle(PHPExcel_Style $pCellStyle = null, $pRange = '') - { - // make sure we have a real style and not supervisor + /** + * Duplicate cell style to a range of cells + * + * Please note that this will overwrite existing cell styles for cells in range! + * + * @param PHPExcel_Style $pCellStyle Cell style to duplicate + * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function duplicateStyle(PHPExcel_Style $pCellStyle = null, $pRange = '') + { + // make sure we have a real style and not supervisor $style = $pCellStyle->getIsSupervisor() ? $pCellStyle->getSharedComponent() : $pCellStyle; // Add the style to the workbook if necessary @@ -1286,123 +1302,123 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable } // Uppercase coordinate - $pRange = strtoupper($pRange); + $pRange = strtoupper($pRange); - // Is it a cell range or a single cell? - $rangeA = ''; - $rangeB = ''; - if (strpos($pRange, ':') === false) { - $rangeA = $pRange; - $rangeB = $pRange; - } else { - list($rangeA, $rangeB) = explode(':', $pRange); - } + // Is it a cell range or a single cell? + $rangeA = ''; + $rangeB = ''; + if (strpos($pRange, ':') === false) { + $rangeA = $pRange; + $rangeB = $pRange; + } else { + list($rangeA, $rangeB) = explode(':', $pRange); + } - // Calculate range outer borders - $rangeStart = PHPExcel_Cell::coordinateFromString($rangeA); - $rangeEnd = PHPExcel_Cell::coordinateFromString($rangeB); + // Calculate range outer borders + $rangeStart = PHPExcel_Cell::coordinateFromString($rangeA); + $rangeEnd = PHPExcel_Cell::coordinateFromString($rangeB); - // Translate column into index - $rangeStart[0] = PHPExcel_Cell::columnIndexFromString($rangeStart[0]) - 1; - $rangeEnd[0] = PHPExcel_Cell::columnIndexFromString($rangeEnd[0]) - 1; + // Translate column into index + $rangeStart[0] = PHPExcel_Cell::columnIndexFromString($rangeStart[0]) - 1; + $rangeEnd[0] = PHPExcel_Cell::columnIndexFromString($rangeEnd[0]) - 1; - // Make sure we can loop upwards on rows and columns - if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) { - $tmp = $rangeStart; - $rangeStart = $rangeEnd; - $rangeEnd = $tmp; - } + // Make sure we can loop upwards on rows and columns + if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) { + $tmp = $rangeStart; + $rangeStart = $rangeEnd; + $rangeEnd = $tmp; + } - // Loop through cells and apply styles - for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { - for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { - $this->getCell(PHPExcel_Cell::stringFromColumnIndex($col) . $row)->setXfIndex($xfIndex); - } - } + // Loop through cells and apply styles + for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { + for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { + $this->getCell(PHPExcel_Cell::stringFromColumnIndex($col) . $row)->setXfIndex($xfIndex); + } + } - return $this; - } + return $this; + } - /** - * Duplicate cell style array to a range of cells - * - * Please note that this will overwrite existing cell styles for cells in range, - * if they are in the styles array. For example, if you decide to set a range of - * cells to font bold, only include font bold in the styles array. - * - * @deprecated - * @param array $pStyles Array containing style information - * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") - * @param boolean $pAdvanced Advanced mode for setting borders. - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function duplicateStyleArray($pStyles = null, $pRange = '', $pAdvanced = true) - { + /** + * Duplicate cell style array to a range of cells + * + * Please note that this will overwrite existing cell styles for cells in range, + * if they are in the styles array. For example, if you decide to set a range of + * cells to font bold, only include font bold in the styles array. + * + * @deprecated + * @param array $pStyles Array containing style information + * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") + * @param boolean $pAdvanced Advanced mode for setting borders. + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function duplicateStyleArray($pStyles = null, $pRange = '', $pAdvanced = true) + { $this->getStyle($pRange)->applyFromArray($pStyles, $pAdvanced); - return $this; - } + return $this; + } - /** - * Set break on a cell - * - * @param string $pCell Cell coordinate (e.g. A1) - * @param int $pBreak Break type (type of PHPExcel_Worksheet::BREAK_*) - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setBreak($pCell = 'A1', $pBreak = PHPExcel_Worksheet::BREAK_NONE) - { - // Uppercase coordinate - $pCell = strtoupper($pCell); + /** + * Set break on a cell + * + * @param string $pCell Cell coordinate (e.g. A1) + * @param int $pBreak Break type (type of PHPExcel_Worksheet::BREAK_*) + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setBreak($pCell = 'A1', $pBreak = PHPExcel_Worksheet::BREAK_NONE) + { + // Uppercase coordinate + $pCell = strtoupper($pCell); - if ($pCell != '') { - $this->_breaks[$pCell] = $pBreak; - } else { - throw new Exception('No cell coordinate specified.'); - } + if ($pCell != '') { + $this->_breaks[$pCell] = $pBreak; + } else { + throw new Exception('No cell coordinate specified.'); + } - return $this; - } + return $this; + } - /** - * Set break on a cell by using numeric cell coordinates - * - * @param int $pColumn Numeric column coordinate of the cell - * @param int $pRow Numeric row coordinate of the cell - * @param int $pBreak Break type (type of PHPExcel_Worksheet::BREAK_*) - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setBreakByColumnAndRow($pColumn = 0, $pRow = 0, $pBreak = PHPExcel_Worksheet::BREAK_NONE) - { - return $this->setBreak(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow, $pBreak); - } + /** + * Set break on a cell by using numeric cell coordinates + * + * @param integer $pColumn Numeric column coordinate of the cell + * @param integer $pRow Numeric row coordinate of the cell + * @param integer $pBreak Break type (type of PHPExcel_Worksheet::BREAK_*) + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setBreakByColumnAndRow($pColumn = 0, $pRow = 1, $pBreak = PHPExcel_Worksheet::BREAK_NONE) + { + return $this->setBreak(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow, $pBreak); + } - /** - * Get breaks - * - * @return array[] - */ - public function getBreaks() - { - return $this->_breaks; - } + /** + * Get breaks + * + * @return array[] + */ + public function getBreaks() + { + return $this->_breaks; + } - /** - * Set merge on a cell range - * - * @param string $pRange Cell range (e.g. A1:E1) - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function mergeCells($pRange = 'A1:A1') - { - // Uppercase coordinate - $pRange = strtoupper($pRange); + /** + * Set merge on a cell range + * + * @param string $pRange Cell range (e.g. A1:E1) + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function mergeCells($pRange = 'A1:A1') + { + // Uppercase coordinate + $pRange = strtoupper($pRange); - if (strpos($pRange,':') !== false) { - $this->_mergeCells[$pRange] = $pRange; + if (strpos($pRange,':') !== false) { + $this->_mergeCells[$pRange] = $pRange; // make sure cells are created @@ -1421,79 +1437,79 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->getCell($aReferences[$i])->setValueExplicit(null, PHPExcel_Cell_DataType::TYPE_NULL); } - } else { - throw new Exception('Merge must be set on a range of cells.'); - } + } else { + throw new Exception('Merge must be set on a range of cells.'); + } - return $this; - } + return $this; + } - /** - * Set merge on a cell range by using numeric cell coordinates - * - * @param int $pColumn1 Numeric column coordinate of the first cell - * @param int $pRow1 Numeric row coordinate of the first cell - * @param int $pColumn2 Numeric column coordinate of the last cell - * @param int $pRow2 Numeric row coordinate of the last cell - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function mergeCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 0, $pColumn2 = 0, $pRow2 = 0) - { - $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; - return $this->mergeCells($cellRange); - } + /** + * Set merge on a cell range by using numeric cell coordinates + * + * @param int $pColumn1 Numeric column coordinate of the first cell + * @param int $pRow1 Numeric row coordinate of the first cell + * @param int $pColumn2 Numeric column coordinate of the last cell + * @param int $pRow2 Numeric row coordinate of the last cell + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function mergeCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1) + { + $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; + return $this->mergeCells($cellRange); + } - /** - * Remove merge on a cell range - * - * @param string $pRange Cell range (e.g. A1:E1) - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function unmergeCells($pRange = 'A1:A1') - { - // Uppercase coordinate - $pRange = strtoupper($pRange); + /** + * Remove merge on a cell range + * + * @param string $pRange Cell range (e.g. A1:E1) + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function unmergeCells($pRange = 'A1:A1') + { + // Uppercase coordinate + $pRange = strtoupper($pRange); - if (strpos($pRange,':') !== false) { - if (isset($this->_mergeCells[$pRange])) { - unset($this->_mergeCells[$pRange]); - } else { - throw new Exception('Cell range ' . $pRange . ' not known as merged.'); - } - } else { - throw new Exception('Merge can only be removed from a range of cells.'); - } + if (strpos($pRange,':') !== false) { + if (isset($this->_mergeCells[$pRange])) { + unset($this->_mergeCells[$pRange]); + } else { + throw new Exception('Cell range ' . $pRange . ' not known as merged.'); + } + } else { + throw new Exception('Merge can only be removed from a range of cells.'); + } - return $this; - } + return $this; + } - /** - * Remove merge on a cell range by using numeric cell coordinates - * - * @param int $pColumn1 Numeric column coordinate of the first cell - * @param int $pRow1 Numeric row coordinate of the first cell - * @param int $pColumn2 Numeric column coordinate of the last cell - * @param int $pRow2 Numeric row coordinate of the last cell - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function unmergeCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 0, $pColumn2 = 0, $pRow2 = 0) - { - $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; - return $this->unmergeCells($cellRange); - } + /** + * Remove merge on a cell range by using numeric cell coordinates + * + * @param int $pColumn1 Numeric column coordinate of the first cell + * @param int $pRow1 Numeric row coordinate of the first cell + * @param int $pColumn2 Numeric column coordinate of the last cell + * @param int $pRow2 Numeric row coordinate of the last cell + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function unmergeCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1) + { + $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; + return $this->unmergeCells($cellRange); + } - /** - * Get merge cells array. - * - * @return array[] - */ - public function getMergeCells() - { - return $this->_mergeCells; - } + /** + * Get merge cells array. + * + * @return array[] + */ + public function getMergeCells() + { + return $this->_mergeCells; + } /** * Set merge cells array for the entire sheet. Use instead mergeCells() to merge @@ -1508,320 +1524,332 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return $this; } + /** + * Set protection on a cell range + * + * @param string $pRange Cell (e.g. A1) or cell range (e.g. A1:E1) + * @param string $pPassword Password to unlock the protection + * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function protectCells($pRange = 'A1', $pPassword = '', $pAlreadyHashed = false) + { + // Uppercase coordinate + $pRange = strtoupper($pRange); + + if (!$pAlreadyHashed) { + $pPassword = PHPExcel_Shared_PasswordHasher::hashPassword($pPassword); + } + $this->_protectedCells[$pRange] = $pPassword; + + return $this; + } + + /** + * Set protection on a cell range by using numeric cell coordinates + * + * @param int $pColumn1 Numeric column coordinate of the first cell + * @param int $pRow1 Numeric row coordinate of the first cell + * @param int $pColumn2 Numeric column coordinate of the last cell + * @param int $pRow2 Numeric row coordinate of the last cell + * @param string $pPassword Password to unlock the protection + * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function protectCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1, $pPassword = '', $pAlreadyHashed = false) + { + $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; + return $this->protectCells($cellRange, $pPassword, $pAlreadyHashed); + } + + /** + * Remove protection on a cell range + * + * @param string $pRange Cell (e.g. A1) or cell range (e.g. A1:E1) + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function unprotectCells($pRange = 'A1') + { + // Uppercase coordinate + $pRange = strtoupper($pRange); + + if (isset($this->_protectedCells[$pRange])) { + unset($this->_protectedCells[$pRange]); + } else { + throw new Exception('Cell range ' . $pRange . ' not known as protected.'); + } + return $this; + } + + /** + * Remove protection on a cell range by using numeric cell coordinates + * + * @param int $pColumn1 Numeric column coordinate of the first cell + * @param int $pRow1 Numeric row coordinate of the first cell + * @param int $pColumn2 Numeric column coordinate of the last cell + * @param int $pRow2 Numeric row coordinate of the last cell + * @param string $pPassword Password to unlock the protection + * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function unprotectCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1, $pPassword = '', $pAlreadyHashed = false) + { + $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; + return $this->unprotectCells($cellRange, $pPassword, $pAlreadyHashed); + } + + /** + * Get protected cells + * + * @return array[] + */ + public function getProtectedCells() + { + return $this->_protectedCells; + } + + /** + * Get Autofilter Range + * + * @return string + */ + public function getAutoFilter() + { + return $this->_autoFilter; + } + + /** + * Set Autofilter Range + * + * @param string $pRange Cell range (i.e. A1:E10) + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setAutoFilter($pRange = '') + { + // Uppercase coordinate + $pRange = strtoupper($pRange); + + if (strpos($pRange,':') !== false) { + $this->_autoFilter = $pRange; + $this->_dirty = true; + } else { + throw new Exception('Autofilter must be set on a range of cells.'); + } + return $this; + } + + /** + * Set Autofilter Range by using numeric cell coordinates + * + * @param int $pColumn1 Numeric column coordinate of the first cell + * @param int $pRow1 Numeric row coordinate of the first cell + * @param int $pColumn2 Numeric column coordinate of the second cell + * @param int $pRow2 Numeric row coordinate of the second cell + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setAutoFilterByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1) + { + return $this->setAutoFilter( + PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 + . ':' . + PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2 + ); + } + /** - * Set protection on a cell range + * Remove autofilter * - * @param string $pRange Cell (e.g. A1) or cell range (e.g. A1:E1) - * @param string $pPassword Password to unlock the protection - * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true - * @throws Exception * @return PHPExcel_Worksheet */ - public function protectCells($pRange = 'A1', $pPassword = '', $pAlreadyHashed = false) + public function removeAutoFilter() { - // Uppercase coordinate - $pRange = strtoupper($pRange); - - if (!$pAlreadyHashed) { - $pPassword = PHPExcel_Shared_PasswordHasher::hashPassword($pPassword); - } - $this->_protectedCells[$pRange] = $pPassword; - + $this->_autoFilter = ''; return $this; } - /** - * Set protection on a cell range by using numeric cell coordinates - * - * @param int $pColumn1 Numeric column coordinate of the first cell - * @param int $pRow1 Numeric row coordinate of the first cell - * @param int $pColumn2 Numeric column coordinate of the last cell - * @param int $pRow2 Numeric row coordinate of the last cell - * @param string $pPassword Password to unlock the protection - * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function protectCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 0, $pColumn2 = 0, $pRow2 = 0, $pPassword = '', $pAlreadyHashed = false) - { - $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; - return $this->protectCells($cellRange, $pPassword, $pAlreadyHashed); - } + /** + * Get Freeze Pane + * + * @return string + */ + public function getFreezePane() + { + return $this->_freezePane; + } - /** - * Remove protection on a cell range - * - * @param string $pRange Cell (e.g. A1) or cell range (e.g. A1:E1) - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function unprotectCells($pRange = 'A1') - { - // Uppercase coordinate - $pRange = strtoupper($pRange); + /** + * Freeze Pane + * + * @param string $pCell Cell (i.e. A1) + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function freezePane($pCell = '') + { + // Uppercase coordinate + $pCell = strtoupper($pCell); - if (isset($this->_protectedCells[$pRange])) { - unset($this->_protectedCells[$pRange]); - } else { - throw new Exception('Cell range ' . $pRange . ' not known as protected.'); - } - return $this; - } + if (strpos($pCell,':') === false && strpos($pCell,',') === false) { + $this->_freezePane = $pCell; + } else { + throw new Exception('Freeze pane can not be set on a range of cells.'); + } + return $this; + } - /** - * Remove protection on a cell range by using numeric cell coordinates - * - * @param int $pColumn1 Numeric column coordinate of the first cell - * @param int $pRow1 Numeric row coordinate of the first cell - * @param int $pColumn2 Numeric column coordinate of the last cell - * @param int $pRow2 Numeric row coordinate of the last cell - * @param string $pPassword Password to unlock the protection - * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function unprotectCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 0, $pColumn2 = 0, $pRow2 = 0, $pPassword = '', $pAlreadyHashed = false) - { - $cellRange = PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2; - return $this->unprotectCells($cellRange, $pPassword, $pAlreadyHashed); - } + /** + * Freeze Pane by using numeric cell coordinates + * + * @param int $pColumn Numeric column coordinate of the cell + * @param int $pRow Numeric row coordinate of the cell + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function freezePaneByColumnAndRow($pColumn = 0, $pRow = 1) + { + return $this->freezePane(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); + } - /** - * Get protected cells - * - * @return array[] - */ - public function getProtectedCells() - { - return $this->_protectedCells; - } + /** + * Unfreeze Pane + * + * @return PHPExcel_Worksheet + */ + public function unfreezePane() + { + return $this->freezePane(''); + } - /** - * Get Autofilter Range - * - * @return string - */ - public function getAutoFilter() - { - return $this->_autoFilter; - } + /** + * Insert a new row, updating all possible related data + * + * @param int $pBefore Insert before this one + * @param int $pNumRows Number of rows to insert + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function insertNewRowBefore($pBefore = 1, $pNumRows = 1) { + if ($pBefore >= 1) { + $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); + $objReferenceHelper->insertNewBefore('A' . $pBefore, 0, $pNumRows, $this); + } else { + throw new Exception("Rows can only be inserted before at least row 1."); + } + return $this; + } - /** - * Set Autofilter Range - * - * @param string $pRange Cell range (i.e. A1:E10) - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setAutoFilter($pRange = '') - { - // Uppercase coordinate - $pRange = strtoupper($pRange); + /** + * Insert a new column, updating all possible related data + * + * @param int $pBefore Insert before this one + * @param int $pNumCols Number of columns to insert + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function insertNewColumnBefore($pBefore = 'A', $pNumCols = 1) { + if (!is_numeric($pBefore)) { + $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); + $objReferenceHelper->insertNewBefore($pBefore . '1', $pNumCols, 0, $this); + } else { + throw new Exception("Column references should not be numeric."); + } + return $this; + } - if (strpos($pRange,':') !== false) { - $this->_autoFilter = $pRange; - } else { - throw new Exception('Autofilter must be set on a range of cells.'); - } - return $this; - } + /** + * Insert a new column, updating all possible related data + * + * @param int $pBefore Insert before this one (numeric column coordinate of the cell) + * @param int $pNumCols Number of columns to insert + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function insertNewColumnBeforeByIndex($pBefore = 0, $pNumCols = 1) { + if ($pBefore >= 0) { + return $this->insertNewColumnBefore(PHPExcel_Cell::stringFromColumnIndex($pBefore), $pNumCols); + } else { + throw new Exception("Columns can only be inserted before at least column A (0)."); + } + } - /** - * Set Autofilter Range by using numeric cell coordinates - * - * @param int $pColumn1 Numeric column coordinate of the first cell - * @param int $pRow1 Numeric row coordinate of the first cell - * @param int $pColumn2 Numeric column coordinate of the second cell - * @param int $pRow2 Numeric row coordinate of the second cell - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setAutoFilterByColumnAndRow($pColumn1 = 0, $pRow1 = 0, $pColumn2 = 0, $pRow2 = 0) - { - return $this->setAutoFilter( - PHPExcel_Cell::stringFromColumnIndex($pColumn1) . $pRow1 - . ':' . - PHPExcel_Cell::stringFromColumnIndex($pColumn2) . $pRow2 - ); - } + /** + * Delete a row, updating all possible related data + * + * @param int $pRow Remove starting with this one + * @param int $pNumRows Number of rows to remove + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function removeRow($pRow = 1, $pNumRows = 1) { + if ($pRow >= 1) { + $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); + $objReferenceHelper->insertNewBefore('A' . ($pRow + $pNumRows), 0, -$pNumRows, $this); + } else { + throw new Exception("Rows to be deleted should at least start from row 1."); + } + return $this; + } - /** - * Get Freeze Pane - * - * @return string - */ - public function getFreezePane() - { - return $this->_freezePane; - } + /** + * Remove a column, updating all possible related data + * + * @param int $pColumn Remove starting with this one + * @param int $pNumCols Number of columns to remove + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function removeColumn($pColumn = 'A', $pNumCols = 1) { + if (!is_numeric($pColumn)) { + $pColumn = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($pColumn) - 1 + $pNumCols); + $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); + $objReferenceHelper->insertNewBefore($pColumn . '1', -$pNumCols, 0, $this); + } else { + throw new Exception("Column references should not be numeric."); + } + return $this; + } - /** - * Freeze Pane - * - * @param string $pCell Cell (i.e. A1) - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function freezePane($pCell = '') - { - // Uppercase coordinate - $pCell = strtoupper($pCell); + /** + * Remove a column, updating all possible related data + * + * @param int $pColumn Remove starting with this one (numeric column coordinate of the cell) + * @param int $pNumCols Number of columns to remove + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function removeColumnByIndex($pColumn = 0, $pNumCols = 1) { + if ($pColumn >= 0) { + return $this->removeColumn(PHPExcel_Cell::stringFromColumnIndex($pColumn), $pNumCols); + } else { + throw new Exception("Columns to be deleted should at least start from column 0"); + } + } - if (strpos($pCell,':') === false && strpos($pCell,',') === false) { - $this->_freezePane = $pCell; - } else { - throw new Exception('Freeze pane can not be set on a range of cells.'); - } - return $this; - } + /** + * Show gridlines? + * + * @return boolean + */ + public function getShowGridlines() { + return $this->_showGridlines; + } - /** - * Freeze Pane by using numeric cell coordinates - * - * @param int $pColumn Numeric column coordinate of the cell - * @param int $pRow Numeric row coordinate of the cell - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function freezePaneByColumnAndRow($pColumn = 0, $pRow = 0) - { - return $this->freezePane(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); - } - - /** - * Unfreeze Pane - * - * @return PHPExcel_Worksheet - */ - public function unfreezePane() - { - return $this->freezePane(''); - } - - /** - * Insert a new row, updating all possible related data - * - * @param int $pBefore Insert before this one - * @param int $pNumRows Number of rows to insert - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function insertNewRowBefore($pBefore = 1, $pNumRows = 1) { - if ($pBefore >= 1) { - $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); - $objReferenceHelper->insertNewBefore('A' . $pBefore, 0, $pNumRows, $this); - } else { - throw new Exception("Rows can only be inserted before at least row 1."); - } - return $this; - } - - /** - * Insert a new column, updating all possible related data - * - * @param int $pBefore Insert before this one - * @param int $pNumCols Number of columns to insert - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function insertNewColumnBefore($pBefore = 'A', $pNumCols = 1) { - if (!is_numeric($pBefore)) { - $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); - $objReferenceHelper->insertNewBefore($pBefore . '1', $pNumCols, 0, $this); - } else { - throw new Exception("Column references should not be numeric."); - } - return $this; - } - - /** - * Insert a new column, updating all possible related data - * - * @param int $pBefore Insert before this one (numeric column coordinate of the cell) - * @param int $pNumCols Number of columns to insert - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function insertNewColumnBeforeByIndex($pBefore = 0, $pNumCols = 1) { - if ($pBefore >= 0) { - return $this->insertNewColumnBefore(PHPExcel_Cell::stringFromColumnIndex($pBefore), $pNumCols); - } else { - throw new Exception("Columns can only be inserted before at least column A (0)."); - } - } - - /** - * Delete a row, updating all possible related data - * - * @param int $pRow Remove starting with this one - * @param int $pNumRows Number of rows to remove - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function removeRow($pRow = 1, $pNumRows = 1) { - if ($pRow >= 1) { - $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); - $objReferenceHelper->insertNewBefore('A' . ($pRow + $pNumRows), 0, -$pNumRows, $this); - } else { - throw new Exception("Rows to be deleted should at least start from row 1."); - } - return $this; - } - - /** - * Remove a column, updating all possible related data - * - * @param int $pColumn Remove starting with this one - * @param int $pNumCols Number of columns to remove - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function removeColumn($pColumn = 'A', $pNumCols = 1) { - if (!is_numeric($pColumn)) { - $pColumn = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($pColumn) - 1 + $pNumCols); - $objReferenceHelper = PHPExcel_ReferenceHelper::getInstance(); - $objReferenceHelper->insertNewBefore($pColumn . '1', -$pNumCols, 0, $this); - } else { - throw new Exception("Column references should not be numeric."); - } - return $this; - } - - /** - * Remove a column, updating all possible related data - * - * @param int $pColumn Remove starting with this one (numeric column coordinate of the cell) - * @param int $pNumCols Number of columns to remove - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function removeColumnByIndex($pColumn = 0, $pNumCols = 1) { - if ($pColumn >= 0) { - return $this->removeColumn(PHPExcel_Cell::stringFromColumnIndex($pColumn), $pNumCols); - } else { - throw new Exception("Columns can only be inserted before at least column A (0)."); - } - } - - /** - * Show gridlines? - * - * @return boolean - */ - public function getShowGridlines() { - return $this->_showGridlines; - } - - /** - * Set show gridlines - * - * @param boolean $pValue Show gridlines (true/false) - * @return PHPExcel_Worksheet - */ - public function setShowGridlines($pValue = false) { - $this->_showGridlines = $pValue; - return $this; - } + /** + * Set show gridlines + * + * @param boolean $pValue Show gridlines (true/false) + * @return PHPExcel_Worksheet + */ + public function setShowGridlines($pValue = false) { + $this->_showGridlines = $pValue; + return $this; + } /** * Print gridlines? @@ -1863,152 +1891,165 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return $this; } - /** - * Show summary below? (Row/Column outlining) - * - * @return boolean - */ - public function getShowSummaryBelow() { - return $this->_showSummaryBelow; - } + /** + * Show summary below? (Row/Column outlining) + * + * @return boolean + */ + public function getShowSummaryBelow() { + return $this->_showSummaryBelow; + } - /** - * Set show summary below - * - * @param boolean $pValue Show summary below (true/false) - * @return PHPExcel_Worksheet - */ - public function setShowSummaryBelow($pValue = true) { - $this->_showSummaryBelow = $pValue; - return $this; - } + /** + * Set show summary below + * + * @param boolean $pValue Show summary below (true/false) + * @return PHPExcel_Worksheet + */ + public function setShowSummaryBelow($pValue = true) { + $this->_showSummaryBelow = $pValue; + return $this; + } - /** - * Show summary right? (Row/Column outlining) - * - * @return boolean - */ - public function getShowSummaryRight() { - return $this->_showSummaryRight; - } + /** + * Show summary right? (Row/Column outlining) + * + * @return boolean + */ + public function getShowSummaryRight() { + return $this->_showSummaryRight; + } - /** - * Set show summary right - * - * @param boolean $pValue Show summary right (true/false) - * @return PHPExcel_Worksheet - */ - public function setShowSummaryRight($pValue = true) { - $this->_showSummaryRight = $pValue; - return $this; - } + /** + * Set show summary right + * + * @param boolean $pValue Show summary right (true/false) + * @return PHPExcel_Worksheet + */ + public function setShowSummaryRight($pValue = true) { + $this->_showSummaryRight = $pValue; + return $this; + } - /** - * Get comments - * - * @return PHPExcel_Comment[] - */ - public function getComments() - { - return $this->_comments; - } + /** + * Get comments + * + * @return PHPExcel_Comment[] + */ + public function getComments() + { + return $this->_comments; + } - /** - * Get comment for cell - * - * @param string $pCellCoordinate Cell coordinate to get comment for - * @return PHPExcel_Comment - * @throws Exception - */ - public function getComment($pCellCoordinate = 'A1') - { - // Uppercase coordinate - $pCellCoordinate = strtoupper($pCellCoordinate); + /** + * Set comments array for the entire sheet. + * + * @param array of PHPExcel_Comment + * @return PHPExcel_Worksheet + */ + public function setComments($pValue = array()) + { + $this->_comments = $pValue; - if (strpos($pCellCoordinate,':') !== false || strpos($pCellCoordinate,',') !== false) { - throw new Exception('Cell coordinate string can not be a range of cells.'); - } else if (strpos($pCellCoordinate,'$') !== false) { - throw new Exception('Cell coordinate string must not be absolute.'); - } else if ($pCellCoordinate == '') { - throw new Exception('Cell coordinate can not be zero-length string.'); - } else { - // Check if we already have a comment for this cell. - // If not, create a new comment. - if (isset($this->_comments[$pCellCoordinate])) { - return $this->_comments[$pCellCoordinate]; - } else { - $newComment = new PHPExcel_Comment(); - $this->_comments[$pCellCoordinate] = $newComment; - return $newComment; - } - } - } + return $this; + } - /** - * Get comment for cell by using numeric cell coordinates - * - * @param int $pColumn Numeric column coordinate of the cell - * @param int $pRow Numeric row coordinate of the cell - * @return PHPExcel_Comment - */ - public function getCommentByColumnAndRow($pColumn = 0, $pRow = 0) - { - return $this->getComment(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); - } - - /** - * Get selected cell - * - * @deprecated - * @return string - */ - public function getSelectedCell() - { - return $this->getSelectedCells(); - } - - /** - * Get active cell - * - * @return string Example: 'A1' - */ - public function getActiveCell() - { - return $this->_activeCell; - } - - /** - * Get selected cells - * - * @return string - */ - public function getSelectedCells() - { - return $this->_selectedCells; - } - - /** - * Selected cell - * - * @param string $pCell Cell (i.e. A1) - * @return PHPExcel_Worksheet - */ - public function setSelectedCell($pCoordinate = 'A1') - { - return $this->setSelectedCells($pCoordinate); - } - - /** - * Select a range of cells. - * - * @param string $pCoordinate Cell range, examples: 'A1', 'B2:G5', 'A:C', '3:6' - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setSelectedCells($pCoordinate = 'A1') - { + /** + * Get comment for cell + * + * @param string $pCellCoordinate Cell coordinate to get comment for + * @return PHPExcel_Comment + * @throws Exception + */ + public function getComment($pCellCoordinate = 'A1') + { // Uppercase coordinate - $pCoordinate = strtoupper($pCoordinate); + $pCellCoordinate = strtoupper($pCellCoordinate); + + if (strpos($pCellCoordinate,':') !== false || strpos($pCellCoordinate,',') !== false) { + throw new Exception('Cell coordinate string can not be a range of cells.'); + } else if (strpos($pCellCoordinate,'$') !== false) { + throw new Exception('Cell coordinate string must not be absolute.'); + } else if ($pCellCoordinate == '') { + throw new Exception('Cell coordinate can not be zero-length string.'); + } else { + // Check if we already have a comment for this cell. + // If not, create a new comment. + if (isset($this->_comments[$pCellCoordinate])) { + return $this->_comments[$pCellCoordinate]; + } else { + $newComment = new PHPExcel_Comment(); + $this->_comments[$pCellCoordinate] = $newComment; + return $newComment; + } + } + } + + /** + * Get comment for cell by using numeric cell coordinates + * + * @param int $pColumn Numeric column coordinate of the cell + * @param int $pRow Numeric row coordinate of the cell + * @return PHPExcel_Comment + */ + public function getCommentByColumnAndRow($pColumn = 0, $pRow = 1) + { + return $this->getComment(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); + } + + /** + * Get selected cell + * + * @deprecated + * @return string + */ + public function getSelectedCell() + { + return $this->getSelectedCells(); + } + + /** + * Get active cell + * + * @return string Example: 'A1' + */ + public function getActiveCell() + { + return $this->_activeCell; + } + + /** + * Get selected cells + * + * @return string + */ + public function getSelectedCells() + { + return $this->_selectedCells; + } + + /** + * Selected cell + * + * @param string $pCell Cell (i.e. A1) + * @return PHPExcel_Worksheet + */ + public function setSelectedCell($pCoordinate = 'A1') + { + return $this->setSelectedCells($pCoordinate); + } + + /** + * Select a range of cells. + * + * @param string $pCoordinate Cell range, examples: 'A1', 'B2:G5', 'A:C', '3:6' + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setSelectedCells($pCoordinate = 'A1') + { + // Uppercase coordinate + $pCoordinate = strtoupper($pCoordinate); // Convert 'A' to 'A:A' $pCoordinate = preg_replace('/^([A-Z]+)$/', '${1}:${1}', $pCoordinate); @@ -2019,137 +2060,212 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Convert 'A:C' to 'A1:C1048576' $pCoordinate = preg_replace('/^([A-Z]+):([A-Z]+)$/', '${1}1:${2}1048576', $pCoordinate); - // Convert '1:3' to 'A1:XFD3' + // Convert '1:3' to 'A1:XFD3' $pCoordinate = preg_replace('/^([0-9]+):([0-9]+)$/', 'A${1}:XFD${2}', $pCoordinate); - if (strpos($pCoordinate,':') !== false || strpos($pCoordinate,',') !== false) { + if (strpos($pCoordinate,':') !== false || strpos($pCoordinate,',') !== false) { list($first, ) = PHPExcel_Cell::splitRange($pCoordinate); $this->_activeCell = $first[0]; } else { $this->_activeCell = $pCoordinate; } $this->_selectedCells = $pCoordinate; - return $this; - } + return $this; + } - /** - * Selected cell by using numeric cell coordinates - * - * @param int $pColumn Numeric column coordinate of the cell - * @param int $pRow Numeric row coordinate of the cell - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function setSelectedCellByColumnAndRow($pColumn = 0, $pRow = 0) - { - return $this->setSelectedCells(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); - } + /** + * Selected cell by using numeric cell coordinates + * + * @param int $pColumn Numeric column coordinate of the cell + * @param int $pRow Numeric row coordinate of the cell + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function setSelectedCellByColumnAndRow($pColumn = 0, $pRow = 1) + { + return $this->setSelectedCells(PHPExcel_Cell::stringFromColumnIndex($pColumn) . $pRow); + } - /** + /** * Get right-to-left * * @return boolean - */ - public function getRightToLeft() { - return $this->_rightToLeft; - } + */ + public function getRightToLeft() { + return $this->_rightToLeft; + } - /** - * Set right-to-left - * - * @param boolean $value Right-to-left true/false - * @return PHPExcel_Worksheet - */ - public function setRightToLeft($value = false) { - $this->_rightToLeft = $value; - return $this; - } + /** + * Set right-to-left + * + * @param boolean $value Right-to-left true/false + * @return PHPExcel_Worksheet + */ + public function setRightToLeft($value = false) { + $this->_rightToLeft = $value; + return $this; + } + + /** + * Fill worksheet from values in array + * + * @param array $source Source array + * @param mixed $nullValue Value in source array that stands for blank cell + * @param string $startCell Insert array starting from this cell address as the top left coordinate + * @param boolean $strictNullComparison Apply strict comparison when testing for null values in the array + * @throws Exception + * @return PHPExcel_Worksheet + */ + public function fromArray($source = null, $nullValue = null, $startCell = 'A1', $strictNullComparison = false) { + if (is_array($source)) { + // Convert a 1-D array to 2-D (for ease of looping) + if (!is_array(end($source))) { + $source = array($source); + } - /** - * Fill worksheet from values in array - * - * @param array $source Source array - * @param mixed $nullValue Value in source array that stands for blank cell - * @throws Exception - * @return PHPExcel_Worksheet - */ - public function fromArray($source = null, $nullValue = null, $pCell = 'A1') { - if (is_array($source)) { // start coordinate - list ($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($pCell); - $startColumn = PHPExcel_Cell::columnIndexFromString($startColumn) - 1; + list ($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($startCell); // Loop through $source - $currentRow = $startRow - 1; - $rowData = null; foreach ($source as $rowData) { - ++$currentRow; - - $rowCount = count($rowData); - for ($i = 0; $i < $rowCount; ++$i) { - if ($rowData[$i] != $nullValue) { - // Set cell value - $this->getCell(PHPExcel_Cell::stringFromColumnIndex($i + $startColumn) . $currentRow) - ->setValue($rowData[$i]); + $currentColumn = $startColumn; + foreach($rowData as $cellValue) { + if ($strictNullComparison) { + if ($cellValue !== $nullValue) { + // Set cell value + $this->getCell($currentColumn . $startRow)->setValue($cellValue); + } + } else { + if ($cellValue != $nullValue) { + // Set cell value + $this->getCell($currentColumn . $startRow)->setValue($cellValue); + } } + ++$currentColumn; + } + ++$startRow; + } + } else { + throw new Exception("Parameter \$source should be an array."); + } + return $this; + } + + /** + * Create array from a range of cells + * + * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1") + * @param mixed $nullValue Value returned in the array entry if a cell doesn't exist + * @param boolean $calculateFormulas Should formulas be calculated? + * @param boolean $formatData Should formatting be applied to cell values? + * @param boolean $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero + * True - Return rows and columns indexed by their actual row and column IDs + * @return array + */ + public function rangeToArray($pRange = 'A1', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) { + // Returnvalue + $returnValue = array(); + + // Identify the range that we need to extract from the worksheet + list($rangeStart, $rangeEnd) = PHPExcel_Cell::rangeBoundaries($pRange); + $minCol = PHPExcel_Cell::stringFromColumnIndex($rangeStart[0] -1); + $minRow = $rangeStart[1]; + $maxCol = PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0] -1); + $maxRow = $rangeEnd[1]; + + $maxCol++; + + // Loop through rows + for ($row = $minRow; $row <= $maxRow; ++$row) { + $c = -1; + // Loop through columns in the current row + for ($col = $minCol; $col != $maxCol; ++$col) { + $rRef = ($returnCellRef) ? $row : $row-1; + $cRef = ($returnCellRef) ? $col : ++$c; + // Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen + // so we test and retrieve directly against _cellCollection + if ($this->_cellCollection->isDataSet($col.$row)) { + // Cell exists + $cell = $this->_cellCollection->getCacheData($col.$row); + if ($cell->getValue() !== null) { + if ($cell->getValue() instanceof PHPExcel_RichText) { + $returnValue[$rRef][$cRef] = $cell->getValue()->getPlainText(); + } else { + if ($calculateFormulas) { + $returnValue[$rRef][$cRef] = $cell->getCalculatedValue(); + } else { + $returnValue[$rRef][$cRef] = $cell->getValue(); + } + } + + if ($formatData) { + $style = $this->_parent->getCellXfByIndex($cell->getXfIndex()); + $returnValue[$rRef][$cRef] = PHPExcel_Style_NumberFormat::toFormattedString($returnValue[$rRef][$cRef], $style->getNumberFormat()->getFormatCode()); + } + } else { + // Cell holds a NULL + $returnValue[$rRef][$cRef] = $nullValue; + } + } else { + // Cell doesn't exist + $returnValue[$rRef][$cRef] = $nullValue; } } - } else { - throw new Exception("Parameter \$source should be an array."); - } - return $this; - } + } - /** - * Create array from worksheet - * - * @param mixed $nullValue Value treated as "null" - * @param boolean $calculateFormulas Should formulas be calculated? - * @return array - */ - public function toArray($nullValue = null, $calculateFormulas = true) { - // Returnvalue - $returnValue = array(); + // Return + return $returnValue; + } - // Garbage collect... - $this->garbageCollect(); - // Get worksheet dimension - $dimension = explode(':', $this->calculateWorksheetDimension()); - $dimension[0] = PHPExcel_Cell::coordinateFromString($dimension[0]); - $dimension[0][0] = PHPExcel_Cell::columnIndexFromString($dimension[0][0]) - 1; - $dimension[1] = PHPExcel_Cell::coordinateFromString($dimension[1]); - $dimension[1][0] = PHPExcel_Cell::columnIndexFromString($dimension[1][0]) - 1; + /** + * Create array from a range of cells + * + * @param string $pNamedRange Name of the Named Range + * @param mixed $nullValue Value returned in the array entry if a cell doesn't exist + * @param boolean $calculateFormulas Should formulas be calculated? + * @param boolean $formatData Should formatting be applied to cell values? + * @param boolean $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero + * True - Return rows and columns indexed by their actual row and column IDs + * @return array + * @throws Exception + */ + public function namedRangeToArray($pNamedRange = '', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) { + $namedRange = PHPExcel_NamedRange::resolveRange($pNamedRange, $this); + if (!is_null($namedRange)) { + $pWorkSheet = $namedRange->getWorksheet(); + $pCellRange = $namedRange->getRange(); - // Loop through cells - for ($row = $dimension[0][1]; $row <= $dimension[1][1]; ++$row) { - for ($column = $dimension[0][0]; $column <= $dimension[1][0]; ++$column) { - // Cell exists? - if ($this->cellExistsByColumnAndRow($column, $row)) { - $cell = $this->getCellByColumnAndRow($column, $row); + return $pWorkSheet->rangeToArray( $pCellRange, + $nullValue, $calculateFormulas, $formatData, $returnCellRef); + } - if ($cell->getValue() instanceof PHPExcel_RichText) { - $returnValue[$row][$column] = $cell->getValue()->getPlainText(); - } else { - if ($calculateFormulas) { - $returnValue[$row][$column] = $cell->getCalculatedValue(); - } else { - $returnValue[$row][$column] = $cell->getValue(); - } - } + throw new Exception('Named Range '.$pNamedRange.' does not exist.'); + } - $style = $this->_parent->getCellXfByIndex($cell->getXfIndex()); - $returnValue[$row][$column] = PHPExcel_Style_NumberFormat::toFormattedString($returnValue[$row][$column], $style->getNumberFormat()->getFormatCode()); - } else { - $returnValue[$row][$column] = $nullValue; - } - } - } + /** + * Create array from worksheet + * + * @param mixed $nullValue Value returned in the array entry if a cell doesn't exist + * @param boolean $calculateFormulas Should formulas be calculated? + * @param boolean $formatData Should formatting be applied to cell values? + * @param boolean $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero + * True - Return rows and columns indexed by their actual row and column IDs + * @return array + */ + public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) { + // Garbage collect... + $this->garbageCollect(); - // Return - return $returnValue; - } + // Identify the range that we need to extract from the worksheet + $maxCol = $this->getHighestColumn(); + $maxRow = $this->getHighestRow(); + + // Return + return $this->rangeToArray( 'A1:'.$maxCol.$maxRow, + $nullValue, $calculateFormulas, $formatData, $returnCellRef); + } /** * Get row iterator @@ -2160,52 +2276,47 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable return new PHPExcel_Worksheet_RowIterator($this); } - /** - * Run PHPExcel garabage collector. - * - * @return PHPExcel_Worksheet - */ - public function garbageCollect() { - // Build a reference table from images - $imageCoordinates = array(); - $iterator = $this->getDrawingCollection()->getIterator(); - while ($iterator->valid()) { - $imageCoordinates[$iterator->current()->getCoordinates()] = true; - - $iterator->next(); - } - + /** + * Run PHPExcel garabage collector. + * + * @return PHPExcel_Worksheet + */ + public function garbageCollect() { + // Build a reference table from images +// $imageCoordinates = array(); +// $iterator = $this->getDrawingCollection()->getIterator(); +// while ($iterator->valid()) { +// $imageCoordinates[$iterator->current()->getCoordinates()] = true; +// +// $iterator->next(); +// } +// // Lookup highest column and highest row if cells are cleaned $highestColumn = -1; - $highestRow = 1; - - // Find cells that can be cleaned - foreach ($this->_cellCollection->getCellList() as $coord) { - list($col,$row) = sscanf($coord,'%[A-Z]%d'); - $column = PHPExcel_Cell::columnIndexFromString($col); + $highestRow = 1; + // Find cells that can be cleaned + $col = $row = array(); + foreach ($this->_cellCollection->getCellList() as $coord) { + list($c,$r) = sscanf($coord,'%[A-Z]%d'); + $row[$r] = $r; + $col[$c] = strlen($c).$c; + } + if (count($row) > 0) { // Determine highest column and row - if ($highestColumn < $column) { - $highestColumn = $column; - } - if ($row > $highestRow) { - $highestRow = $row; - } - } + $highestRow = max($row); + $highestColumn = PHPExcel_Cell::columnIndexFromString(substr(max($col),1)); + } - // Loop through column dimensions - foreach ($this->_columnDimensions as $dimension) { - if ($highestColumn < PHPExcel_Cell::columnIndexFromString($dimension->getColumnIndex())) { - $highestColumn = PHPExcel_Cell::columnIndexFromString($dimension->getColumnIndex()); - } - } + // Loop through column dimensions + foreach ($this->_columnDimensions as $dimension) { + $highestColumn = max($highestColumn,PHPExcel_Cell::columnIndexFromString($dimension->getColumnIndex())); + } - // Loop through row dimensions - foreach ($this->_rowDimensions as $dimension) { - if ($highestRow < $dimension->getRowIndex()) { - $highestRow = $dimension->getRowIndex(); - } - } + // Loop through row dimensions + foreach ($this->_rowDimensions as $dimension) { + $highestRow = max($highestRow,$dimension->getRowIndex()); + } // Cache values if ($highestColumn < 0) { @@ -2216,8 +2327,8 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $this->_cachedHighestRow = $highestRow; // Return - return $this; - } + return $this; + } /** * Get hash code @@ -2225,52 +2336,41 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * @return string Hash code */ public function getHashCode() { - return md5( - $this->_title - . $this->_autoFilter - . ($this->_protection->isProtectionEnabled() ? 't' : 'f') - //. $this->calculateWorksheetDimension() - . __CLASS__ - ); - } + if ($this->_dirty) { + $this->_hash = md5( $this->_title . + $this->_autoFilter . + ($this->_protection->isProtectionEnabled() ? 't' : 'f') . + __CLASS__ + ); + $this->_dirty = false; + } + return $this->_hash; + } - /** - * Extract worksheet title from range. - * - * Example: extractSheetTitle('test!A1') ==> 'A1' - * Example: extractSheetTitle('test!A1', true) ==> array('test', 'A1'); - * - * @param string $pRange Range to extract title from - * @param bool $returnRange Return range? (see example) - * @return mixed - */ - public static function extractSheetTitle($pRange, $returnRange = false) { - // Sheet title included? - if (strpos($pRange, '!') === false) { - return ''; - } + /** + * Extract worksheet title from range. + * + * Example: extractSheetTitle("testSheet!A1") ==> 'A1' + * Example: extractSheetTitle("'testSheet 1'!A1", true) ==> array('testSheet 1', 'A1'); + * + * @param string $pRange Range to extract title from + * @param bool $returnRange Return range? (see example) + * @return mixed + */ + public static function extractSheetTitle($pRange, $returnRange = false) { + // Sheet title included? + if (($sep = strpos($pRange, '!')) === false) { + return ''; + } - // Position of separator exclamation mark - $sep = strrpos($pRange, '!'); + if ($returnRange) { + return array( trim(substr($pRange, 0, $sep),"'"), + substr($pRange, $sep + 1) + ); + } - // Extract sheet title - $reference[0] = substr($pRange, 0, $sep); - $reference[1] = substr($pRange, $sep + 1); - - // Strip possible enclosing single quotes - if (strpos($reference[0], '\'') === 0) { - $reference[0] = substr($reference[0], 1); - } - if (strrpos($reference[0], '\'') === strlen($reference[0]) - 1) { - $reference[0] = substr($reference[0], 0, strlen($reference[0]) - 1); - } - - if ($returnRange) { - return $reference; - } else { - return $reference[1]; - } - } + return substr($pRange, $sep + 1); + } /** * Get hyperlink @@ -2293,7 +2393,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * Set hyperlnk * * @param string $pCellCoordinate Cell coordinate to insert hyperlink - * @param PHPExcel_Cell_Hyperlink $pHyperlink + * @param PHPExcel_Cell_Hyperlink $pHyperlink * @return PHPExcel_Worksheet */ public function setHyperlink($pCellCoordinate = 'A1', PHPExcel_Cell_Hyperlink $pHyperlink = null) @@ -2348,7 +2448,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable * Set data validation * * @param string $pCellCoordinate Cell coordinate to insert data validation - * @param PHPExcel_Cell_DataValidation $pDataValidation + * @param PHPExcel_Cell_DataValidation $pDataValidation * @return PHPExcel_Worksheet */ public function setDataValidation($pCellCoordinate = 'A1', PHPExcel_Cell_DataValidation $pDataValidation = null) @@ -2385,8 +2485,8 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable /** * Accepts a range, returning it as a range that falls within the current highest row and column of the worksheet * - * @param string $range - * @return string Adjusted range value + * @param string $range + * @return string Adjusted range value */ public function shrinkRangeToFit($range) { $maxCol = $this->getHighestColumn(); @@ -2471,6 +2571,9 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $newCollection = clone $this->_cellCollection; $newCollection->copyCellCollection($this); $this->_cellCollection = $newCollection; + } elseif ($key == '_drawingCollection') { + $newCollection = clone $this->_drawingCollection; + $this->_drawingCollection = $newCollection; } else { $this->{$key} = unserialize(serialize($val)); } diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/BaseDrawing.php b/libraries/PHPExcel/PHPExcel/Worksheet/BaseDrawing.php index 511643bf4..6d6c56a65 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/BaseDrawing.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/BaseDrawing.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_BaseDrawing implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/CellIterator.php b/libraries/PHPExcel/PHPExcel/Worksheet/CellIterator.php index 630e089d1..75904eab9 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/CellIterator.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/CellIterator.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,7 +33,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_CellIterator extends CachingIterator { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/ColumnDimension.php b/libraries/PHPExcel/PHPExcel/Worksheet/ColumnDimension.php index 30b00358b..227b4df10 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/ColumnDimension.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/ColumnDimension.php @@ -2,27 +2,27 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,17 +31,17 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_ColumnDimension -{ +{ /** * Column index * * @var int */ private $_columnIndex; - + /** * Column width * @@ -49,35 +49,35 @@ class PHPExcel_Worksheet_ColumnDimension * * @var double */ - private $_width; - + private $_width = -1; + /** * Auto size? * * @var bool */ - private $_autoSize; - + private $_autoSize = false; + /** * Visible? * * @var bool */ - private $_visible; - + private $_visible = true; + /** * Outline level * * @var int */ - private $_outlineLevel = 0; - + private $_outlineLevel = 0; + /** * Collapsed * * @var bool */ - private $_collapsed; + private $_collapsed = false; /** * Index to cellXf @@ -95,16 +95,11 @@ class PHPExcel_Worksheet_ColumnDimension { // Initialise values $this->_columnIndex = $pIndex; - $this->_width = -1; - $this->_autoSize = false; - $this->_visible = true; - $this->_outlineLevel = 0; - $this->_collapsed = false; // set default index to cellXf $this->_xfIndex = 0; } - + /** * Get ColumnIndex * @@ -113,7 +108,7 @@ class PHPExcel_Worksheet_ColumnDimension public function getColumnIndex() { return $this->_columnIndex; } - + /** * Set ColumnIndex * @@ -124,7 +119,7 @@ class PHPExcel_Worksheet_ColumnDimension $this->_columnIndex = $pValue; return $this; } - + /** * Get Width * @@ -133,7 +128,7 @@ class PHPExcel_Worksheet_ColumnDimension public function getWidth() { return $this->_width; } - + /** * Set Width * @@ -144,7 +139,7 @@ class PHPExcel_Worksheet_ColumnDimension $this->_width = $pValue; return $this; } - + /** * Get Auto Size * @@ -153,7 +148,7 @@ class PHPExcel_Worksheet_ColumnDimension public function getAutoSize() { return $this->_autoSize; } - + /** * Set Auto Size * @@ -164,7 +159,7 @@ class PHPExcel_Worksheet_ColumnDimension $this->_autoSize = $pValue; return $this; } - + /** * Get Visible * @@ -173,7 +168,7 @@ class PHPExcel_Worksheet_ColumnDimension public function getVisible() { return $this->_visible; } - + /** * Set Visible * @@ -184,7 +179,7 @@ class PHPExcel_Worksheet_ColumnDimension $this->_visible = $pValue; return $this; } - + /** * Get Outline Level * @@ -193,7 +188,7 @@ class PHPExcel_Worksheet_ColumnDimension public function getOutlineLevel() { return $this->_outlineLevel; } - + /** * Set Outline Level * @@ -207,11 +202,11 @@ class PHPExcel_Worksheet_ColumnDimension if ($pValue < 0 || $pValue > 7) { throw new Exception("Outline level must range between 0 and 7."); } - + $this->_outlineLevel = $pValue; return $this; } - + /** * Get Collapsed * @@ -220,7 +215,7 @@ class PHPExcel_Worksheet_ColumnDimension public function getCollapsed() { return $this->_collapsed; } - + /** * Set Collapsed * @@ -231,7 +226,7 @@ class PHPExcel_Worksheet_ColumnDimension $this->_collapsed = $pValue; return $this; } - + /** * Get index to cellXf * diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/Drawing.php b/libraries/PHPExcel/PHPExcel/Worksheet/Drawing.php index 537f9f3d3..3a24b8a32 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/Drawing.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/Drawing.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet_Drawing - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet_Drawing - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_Drawing extends PHPExcel_Worksheet_BaseDrawing implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/Drawing/Shadow.php b/libraries/PHPExcel/PHPExcel/Worksheet/Drawing/Shadow.php index 053ab0dd8..2366a799b 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/Drawing/Shadow.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/Drawing/Shadow.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet_Drawing - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet_Drawing - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_Drawing_Shadow implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooter.php b/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooter.php index 9d2708d6a..8cae5526d 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooter.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooter.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -91,7 +91,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_HeaderFooter { @@ -108,70 +108,70 @@ class PHPExcel_Worksheet_HeaderFooter * * @var string */ - private $_oddHeader; + private $_oddHeader = ''; /** * OddFooter * * @var string */ - private $_oddFooter; + private $_oddFooter = ''; /** * EvenHeader * * @var string */ - private $_evenHeader; + private $_evenHeader = ''; /** * EvenFooter * * @var string */ - private $_evenFooter; + private $_evenFooter = ''; /** * FirstHeader * * @var string */ - private $_firstHeader; + private $_firstHeader = ''; /** * FirstFooter * * @var string */ - private $_firstFooter; + private $_firstFooter = ''; /** * Different header for Odd/Even, defaults to false * * @var boolean */ - private $_differentOddEven; + private $_differentOddEven = false; /** * Different header for first page, defaults to false * * @var boolean */ - private $_differentFirst; + private $_differentFirst = false; /** * Scale with document, defaults to true * * @var boolean */ - private $_scaleWithDocument; + private $_scaleWithDocument = true; /** * Align with margins, defaults to true * * @var boolean */ - private $_alignWithMargins; + private $_alignWithMargins = true; /** * Header/footer images @@ -185,18 +185,6 @@ class PHPExcel_Worksheet_HeaderFooter */ public function __construct() { - // Initialise values - $this->_oddHeader = ''; - $this->_oddFooter = ''; - $this->_evenHeader = ''; - $this->_evenFooter = ''; - $this->_firstHeader = ''; - $this->_firstFooter = ''; - $this->_differentOddEven = false; - $this->_differentFirst = false; - $this->_scaleWithDocument = true; - $this->_alignWithMargins = true; - $this->_headerFooterImages = array(); } /** diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooterDrawing.php b/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooterDrawing.php index f6142613b..15e1424aa 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooterDrawing.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/HeaderFooterDrawing.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_HeaderFooterDrawing extends PHPExcel_Worksheet_Drawing implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/MemoryDrawing.php b/libraries/PHPExcel/PHPExcel/Worksheet/MemoryDrawing.php index a43e6a92e..71ac25104 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/MemoryDrawing.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/MemoryDrawing.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_MemoryDrawing extends PHPExcel_Worksheet_BaseDrawing implements PHPExcel_IComparable { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/PageMargins.php b/libraries/PHPExcel/PHPExcel/Worksheet/PageMargins.php index 155b976dd..6490f61ae 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/PageMargins.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/PageMargins.php @@ -2,27 +2,27 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,66 +31,59 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_PageMargins -{ +{ /** * Left * * @var double */ - private $_left; - + private $_left = 0.7; + /** * Right * * @var double */ - private $_right; - + private $_right = 0.7; + /** * Top * * @var double */ - private $_top; - + private $_top = 0.75; + /** * Bottom * * @var double */ - private $_bottom; - + private $_bottom = 0.75; + /** * Header * * @var double */ - private $_header; - + private $_header = 0.3; + /** * Footer * * @var double */ - private $_footer; - + private $_footer = 0.3; + /** * Create a new PHPExcel_Worksheet_PageMargins */ public function __construct() { - // Initialise values - $this->_left = 0.7; - $this->_right = 0.7; - $this->_top = 0.75; - $this->_bottom = 0.75; - $this->_header = 0.3; - $this->_footer = 0.3; } - + /** * Get Left * @@ -99,7 +92,7 @@ class PHPExcel_Worksheet_PageMargins public function getLeft() { return $this->_left; } - + /** * Set Left * @@ -110,7 +103,7 @@ class PHPExcel_Worksheet_PageMargins $this->_left = $pValue; return $this; } - + /** * Get Right * @@ -119,7 +112,7 @@ class PHPExcel_Worksheet_PageMargins public function getRight() { return $this->_right; } - + /** * Set Right * @@ -130,7 +123,7 @@ class PHPExcel_Worksheet_PageMargins $this->_right = $pValue; return $this; } - + /** * Get Top * @@ -139,7 +132,7 @@ class PHPExcel_Worksheet_PageMargins public function getTop() { return $this->_top; } - + /** * Set Top * @@ -150,7 +143,7 @@ class PHPExcel_Worksheet_PageMargins $this->_top = $pValue; return $this; } - + /** * Get Bottom * @@ -159,7 +152,7 @@ class PHPExcel_Worksheet_PageMargins public function getBottom() { return $this->_bottom; } - + /** * Set Bottom * @@ -170,7 +163,7 @@ class PHPExcel_Worksheet_PageMargins $this->_bottom = $pValue; return $this; } - + /** * Get Header * @@ -179,7 +172,7 @@ class PHPExcel_Worksheet_PageMargins public function getHeader() { return $this->_header; } - + /** * Set Header * @@ -190,7 +183,7 @@ class PHPExcel_Worksheet_PageMargins $this->_header = $pValue; return $this; } - + /** * Get Footer * @@ -199,7 +192,7 @@ class PHPExcel_Worksheet_PageMargins public function getFooter() { return $this->_footer; } - + /** * Set Footer * @@ -210,7 +203,7 @@ class PHPExcel_Worksheet_PageMargins $this->_footer = $pValue; return $this; } - + /** * Implement PHP __clone to create a deep clone, not just a shallow copy. */ diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/PageSetup.php b/libraries/PHPExcel/PHPExcel/Worksheet/PageSetup.php index 8e615f7d8..beeaeeacf 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/PageSetup.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/PageSetup.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -102,7 +102,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_PageSetup { @@ -189,14 +189,14 @@ class PHPExcel_Worksheet_PageSetup * * @var int */ - private $_paperSize; + private $_paperSize = PHPExcel_Worksheet_PageSetup::PAPERSIZE_LETTER; /** * Orientation * * @var string */ - private $_orientation; + private $_orientation = PHPExcel_Worksheet_PageSetup::ORIENTATION_DEFAULT; /** * Scale (Print Scale) @@ -206,7 +206,7 @@ class PHPExcel_Worksheet_PageSetup * * @var int? */ - private $_scale; + private $_scale = 100; /** * Fit To Page @@ -214,7 +214,7 @@ class PHPExcel_Worksheet_PageSetup * * @var boolean */ - private $_fitToPage; + private $_fitToPage = false; /** * Fit To Height @@ -222,7 +222,7 @@ class PHPExcel_Worksheet_PageSetup * * @var int? */ - private $_fitToHeight; + private $_fitToHeight = 1; /** * Fit To Width @@ -230,7 +230,7 @@ class PHPExcel_Worksheet_PageSetup * * @var int? */ - private $_fitToWidth; + private $_fitToWidth = 1; /** * Columns to repeat at left @@ -279,19 +279,6 @@ class PHPExcel_Worksheet_PageSetup */ public function __construct() { - // Initialise values - $this->_paperSize = PHPExcel_Worksheet_PageSetup::PAPERSIZE_LETTER; - $this->_orientation = PHPExcel_Worksheet_PageSetup::ORIENTATION_DEFAULT; - $this->_scale = 100; - $this->_fitToPage = false; - $this->_fitToHeight = 1; - $this->_fitToWidth = 1; - $this->_columnsToRepeatAtLeft = array('', ''); - $this->_rowsToRepeatAtTop = array(0, 0); - $this->_horizontalCentered = false; - $this->_verticalCentered = false; - $this->_printArea = null; - $this->_firstPageNumber = null; } /** diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/Protection.php b/libraries/PHPExcel/PHPExcel/Worksheet/Protection.php index f60a265d6..17d253903 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/Protection.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/Protection.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_Protection { @@ -40,143 +40,125 @@ class PHPExcel_Worksheet_Protection * * @var boolean */ - private $_sheet; + private $_sheet = false; /** * Objects * * @var boolean */ - private $_objects; + private $_objects = false; /** * Scenarios * * @var boolean */ - private $_scenarios; + private $_scenarios = false; /** * Format cells * * @var boolean */ - private $_formatCells; + private $_formatCells = false; /** * Format columns * * @var boolean */ - private $_formatColumns; + private $_formatColumns = false; /** * Format rows * * @var boolean */ - private $_formatRows; + private $_formatRows = false; /** * Insert columns * * @var boolean */ - private $_insertColumns; + private $_insertColumns = false; /** * Insert rows * * @var boolean */ - private $_insertRows; + private $_insertRows = false; /** * Insert hyperlinks * * @var boolean */ - private $_insertHyperlinks; + private $_insertHyperlinks = false; /** * Delete columns * * @var boolean */ - private $_deleteColumns; + private $_deleteColumns = false; /** * Delete rows * * @var boolean */ - private $_deleteRows; + private $_deleteRows = false; /** * Select locked cells * * @var boolean */ - private $_selectLockedCells; + private $_selectLockedCells = false; /** * Sort * * @var boolean */ - private $_sort; + private $_sort = false; /** * AutoFilter * * @var boolean */ - private $_autoFilter; + private $_autoFilter = false; /** * Pivot tables * * @var boolean */ - private $_pivotTables; + private $_pivotTables = false; /** * Select unlocked cells * * @var boolean */ - private $_selectUnlockedCells; + private $_selectUnlockedCells = false; /** * Password * * @var string */ - private $_password; + private $_password = ''; /** * Create a new PHPExcel_Worksheet_Protection */ public function __construct() { - // Initialise values - $this->_sheet = false; - $this->_objects = false; - $this->_scenarios = false; - $this->_formatCells = false; - $this->_formatColumns = false; - $this->_formatRows = false; - $this->_insertColumns = false; - $this->_insertRows = false; - $this->_insertHyperlinks = false; - $this->_deleteColumns = false; - $this->_deleteRows = false; - $this->_selectLockedCells = false; - $this->_sort = false; - $this->_autoFilter = false; - $this->_pivotTables = false; - $this->_selectUnlockedCells = false; - $this->_password = ''; } /** diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/Row.php b/libraries/PHPExcel/PHPExcel/Worksheet/Row.php index 7311721c6..fe5e0c921 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/Row.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/Row.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,7 +33,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_Row { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/RowDimension.php b/libraries/PHPExcel/PHPExcel/Worksheet/RowDimension.php index 153024f1a..f1de4f678 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/RowDimension.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/RowDimension.php @@ -2,27 +2,27 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,17 +31,17 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_RowDimension -{ +{ /** * Row index * * @var int */ private $_rowIndex; - + /** * Row height (in pt) * @@ -49,28 +49,28 @@ class PHPExcel_Worksheet_RowDimension * * @var double */ - private $_rowHeight; - + private $_rowHeight = -1; + /** * Visible? * * @var bool */ - private $_visible; - + private $_visible = true; + /** * Outline level * * @var int */ - private $_outlineLevel = 0; - + private $_outlineLevel = 0; + /** * Collapsed * * @var bool */ - private $_collapsed; + private $_collapsed = false; /** * Index to cellXf. Null value means row has no explicit cellXf format. @@ -88,15 +88,11 @@ class PHPExcel_Worksheet_RowDimension { // Initialise values $this->_rowIndex = $pIndex; - $this->_rowHeight = -1; - $this->_visible = true; - $this->_outlineLevel = 0; - $this->_collapsed = false; // set row dimension as unformatted by default $this->_xfIndex = null; } - + /** * Get Row Index * @@ -105,7 +101,7 @@ class PHPExcel_Worksheet_RowDimension public function getRowIndex() { return $this->_rowIndex; } - + /** * Set Row Index * @@ -116,7 +112,7 @@ class PHPExcel_Worksheet_RowDimension $this->_rowIndex = $pValue; return $this; } - + /** * Get Row Height * @@ -125,7 +121,7 @@ class PHPExcel_Worksheet_RowDimension public function getRowHeight() { return $this->_rowHeight; } - + /** * Set Row Height * @@ -136,7 +132,7 @@ class PHPExcel_Worksheet_RowDimension $this->_rowHeight = $pValue; return $this; } - + /** * Get Visible * @@ -145,7 +141,7 @@ class PHPExcel_Worksheet_RowDimension public function getVisible() { return $this->_visible; } - + /** * Set Visible * @@ -156,7 +152,7 @@ class PHPExcel_Worksheet_RowDimension $this->_visible = $pValue; return $this; } - + /** * Get Outline Level * @@ -165,7 +161,7 @@ class PHPExcel_Worksheet_RowDimension public function getOutlineLevel() { return $this->_outlineLevel; } - + /** * Set Outline Level * @@ -179,11 +175,11 @@ class PHPExcel_Worksheet_RowDimension if ($pValue < 0 || $pValue > 7) { throw new Exception("Outline level must range between 0 and 7."); } - + $this->_outlineLevel = $pValue; return $this; } - + /** * Get Collapsed * @@ -192,7 +188,7 @@ class PHPExcel_Worksheet_RowDimension public function getCollapsed() { return $this->_collapsed; } - + /** * Set Collapsed * diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/RowIterator.php b/libraries/PHPExcel/PHPExcel/Worksheet/RowIterator.php index e0f91fcfe..2f16d138f 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/RowIterator.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/RowIterator.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,7 +33,7 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_RowIterator extends CachingIterator { diff --git a/libraries/PHPExcel/PHPExcel/Worksheet/SheetView.php b/libraries/PHPExcel/PHPExcel/Worksheet/SheetView.php index fdfe00146..84a0ca896 100644 --- a/libraries/PHPExcel/PHPExcel/Worksheet/SheetView.php +++ b/libraries/PHPExcel/PHPExcel/Worksheet/SheetView.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,36 +31,33 @@ * * @category PHPExcel * @package PHPExcel_Worksheet - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Worksheet_SheetView { /** * ZoomScale - * + * * Valid values range from 10 to 400. * * @var int */ - private $_zoomScale; + private $_zoomScale = 100; /** * ZoomScaleNormal - * + * * Valid values range from 10 to 400. * * @var int */ - private $_zoomScaleNormal; + private $_zoomScaleNormal = 100; /** * Create a new PHPExcel_Worksheet_SheetView */ public function __construct() { - // Initialise values - $this->_zoomScale = 100; - $this->_zoomScaleNormal = 100; } /** @@ -91,7 +88,7 @@ class PHPExcel_Worksheet_SheetView } return $this; } - + /** * Get ZoomScaleNormal * diff --git a/libraries/PHPExcel/PHPExcel/WorksheetIterator.php b/libraries/PHPExcel/PHPExcel/WorksheetIterator.php index 87f8b2955..fcf20351c 100644 --- a/libraries/PHPExcel/PHPExcel/WorksheetIterator.php +++ b/libraries/PHPExcel/PHPExcel/WorksheetIterator.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -33,7 +33,7 @@ * * @category PHPExcel * @package PHPExcel - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_WorksheetIterator extends CachingIterator { diff --git a/libraries/PHPExcel/PHPExcel/Writer/CSV.php b/libraries/PHPExcel/PHPExcel/Writer/CSV.php index 765244dcd..aa50de78c 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/CSV.php +++ b/libraries/PHPExcel/PHPExcel/Writer/CSV.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Writer + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Writer_CSV * * @category PHPExcel - * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Writer + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_CSV implements PHPExcel_Writer_IWriter { /** @@ -46,28 +46,28 @@ class PHPExcel_Writer_CSV implements PHPExcel_Writer_IWriter { * * @var string */ - private $_delimiter; + private $_delimiter = ','; /** * Enclosure * * @var string */ - private $_enclosure; + private $_enclosure = '"'; /** * Line ending * * @var string */ - private $_lineEnding; + private $_lineEnding = PHP_EOL; /** * Sheet index to write * * @var int */ - private $_sheetIndex; + private $_sheetIndex = 0; /** * Pre-calculate formulas @@ -86,21 +86,17 @@ class PHPExcel_Writer_CSV implements PHPExcel_Writer_IWriter { /** * Create a new PHPExcel_Writer_CSV * - * @param PHPExcel $phpExcel PHPExcel object + * @param PHPExcel $phpExcel PHPExcel object */ public function __construct(PHPExcel $phpExcel) { - $this->_phpExcel = $phpExcel; - $this->_delimiter = ','; - $this->_enclosure = '"'; - $this->_lineEnding = PHP_EOL; - $this->_sheetIndex = 0; + $this->_phpExcel = $phpExcel; } /** * Save PHPExcel to file * - * @param string $pFileName - * @throws Exception + * @param string $pFileName + * @throws Exception */ public function save($pFilename = null) { // Fetch sheet @@ -112,7 +108,7 @@ class PHPExcel_Writer_CSV implements PHPExcel_Writer_IWriter { PHPExcel_Calculation::setArrayReturnType(PHPExcel_Calculation::RETURN_ARRAY_AS_VALUE); // Open file - $fileHandle = fopen($pFilename, 'w'); + $fileHandle = fopen($pFilename, 'wb+'); if ($fileHandle === false) { throw new Exception("Could not open file $pFilename for writing."); } @@ -248,7 +244,7 @@ class PHPExcel_Writer_CSV implements PHPExcel_Writer_IWriter { * @throws Exception */ private function _writeLine($pFileHandle = null, $pValues = null) { - if (!is_null($pFileHandle) && is_array($pValues)) { + if (is_array($pValues)) { // No leading delimiter $writeDelimiter = false; @@ -280,23 +276,23 @@ class PHPExcel_Writer_CSV implements PHPExcel_Writer_IWriter { } } - /** - * Get Pre-Calculate Formulas - * - * @return boolean - */ - public function getPreCalculateFormulas() { - return $this->_preCalculateFormulas; - } + /** + * Get Pre-Calculate Formulas + * + * @return boolean + */ + public function getPreCalculateFormulas() { + return $this->_preCalculateFormulas; + } - /** - * Set Pre-Calculate Formulas - * - * @param boolean $pValue Pre-Calculate Formulas? - * @return PHPExcel_Writer_CSV - */ - public function setPreCalculateFormulas($pValue = true) { - $this->_preCalculateFormulas = $pValue; - return $this; - } + /** + * Set Pre-Calculate Formulas + * + * @param boolean $pValue Pre-Calculate Formulas? + * @return PHPExcel_Writer_CSV + */ + public function setPreCalculateFormulas($pValue = true) { + $this->_preCalculateFormulas = $pValue; + return $this; + } } diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007.php index b9f7464e6..ebc51c6ec 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter { @@ -54,7 +54,7 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter * * @var PHPExcel_Writer_Excel2007_WriterPart[] */ - private $_writerParts; + private $_writerParts = array(); /** * Private PHPExcel @@ -68,7 +68,7 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter * * @var string[] */ - private $_stringTable; + private $_stringTable = array(); /** * Private unique PHPExcel_Style_Conditional HashTable @@ -124,7 +124,7 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter * * @var string */ - private $_diskCachingDirectory; + private $_diskCachingDirectory = './'; /** * Create a new PHPExcel_Writer_Excel2007 @@ -136,34 +136,32 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter // Assign PHPExcel $this->setPHPExcel($pPHPExcel); - // Set up disk caching location - $this->_diskCachingDirectory = './'; + $writerPartsArray = array( 'stringtable' => 'PHPExcel_Writer_Excel2007_StringTable', + 'contenttypes' => 'PHPExcel_Writer_Excel2007_ContentTypes', + 'docprops' => 'PHPExcel_Writer_Excel2007_DocProps', + 'rels' => 'PHPExcel_Writer_Excel2007_Rels', + 'theme' => 'PHPExcel_Writer_Excel2007_Theme', + 'style' => 'PHPExcel_Writer_Excel2007_Style', + 'workbook' => 'PHPExcel_Writer_Excel2007_Workbook', + 'worksheet' => 'PHPExcel_Writer_Excel2007_Worksheet', + 'drawing' => 'PHPExcel_Writer_Excel2007_Drawing', + 'comments' => 'PHPExcel_Writer_Excel2007_Comments' + ); - // Initialise writer parts - $this->_writerParts['stringtable'] = new PHPExcel_Writer_Excel2007_StringTable(); - $this->_writerParts['contenttypes'] = new PHPExcel_Writer_Excel2007_ContentTypes(); - $this->_writerParts['docprops'] = new PHPExcel_Writer_Excel2007_DocProps(); - $this->_writerParts['rels'] = new PHPExcel_Writer_Excel2007_Rels(); - $this->_writerParts['theme'] = new PHPExcel_Writer_Excel2007_Theme(); - $this->_writerParts['style'] = new PHPExcel_Writer_Excel2007_Style(); - $this->_writerParts['workbook'] = new PHPExcel_Writer_Excel2007_Workbook(); - $this->_writerParts['worksheet'] = new PHPExcel_Writer_Excel2007_Worksheet(); - $this->_writerParts['drawing'] = new PHPExcel_Writer_Excel2007_Drawing(); - $this->_writerParts['comments'] = new PHPExcel_Writer_Excel2007_Comments(); - - // Assign parent IWriter - foreach ($this->_writerParts as $writer) { - $writer->setParentWriter($this); + // Initialise writer parts + // and Assign their parent IWriters + foreach ($writerPartsArray as $writer => $class) { + $this->_writerParts[$writer] = new $class($this); } + $hashTablesArray = array( '_stylesConditionalHashTable', '_fillHashTable', '_fontHashTable', + '_bordersHashTable', '_numFmtHashTable', '_drawingHashTable' + ); + // Set HashTable variables - $this->_stringTable = array(); - $this->_stylesConditionalHashTable = new PHPExcel_HashTable(); - $this->_fillHashTable = new PHPExcel_HashTable(); - $this->_fontHashTable = new PHPExcel_HashTable(); - $this->_bordersHashTable = new PHPExcel_HashTable(); - $this->_numFmtHashTable = new PHPExcel_HashTable(); - $this->_drawingHashTable = new PHPExcel_HashTable(); + foreach ($hashTablesArray as $tableName) { + $this->$tableName = new PHPExcel_HashTable(); + } } /** @@ -172,7 +170,7 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter * @param string $pPartName Writer part name * @return PHPExcel_Writer_Excel2007_WriterPart */ - function getWriterPart($pPartName = '') { + public function getWriterPart($pPartName = '') { if ($pPartName != '' && isset($this->_writerParts[strtolower($pPartName)])) { return $this->_writerParts[strtolower($pPartName)]; } else { @@ -188,7 +186,7 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter */ public function save($pFilename = null) { - if (!is_null($this->_spreadSheet)) { + if ($this->_spreadSheet !== NULL) { // garbage collect $this->_spreadSheet->garbageCollect(); @@ -223,8 +221,12 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter $this->_drawingHashTable->addFromSource( $this->getWriterPart('Drawing')->allDrawings($this->_spreadSheet) ); // Create new ZIP file and open it for writing - $objZip = new ZipArchive(); + $zipClass = PHPExcel_Settings::getZipClass(); + $objZip = new $zipClass(); + if (file_exists($pFilename)) { + unlink($pFilename); + } // Try opening the ZIP file if ($objZip->open($pFilename, ZIPARCHIVE::OVERWRITE) !== true) { if ($objZip->open($pFilename, ZIPARCHIVE::CREATE) !== true) { @@ -242,6 +244,10 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter // Add document properties to ZIP file $objZip->addFromString('docProps/app.xml', $this->getWriterPart('DocProps')->writeDocPropsApp($this->_spreadSheet)); $objZip->addFromString('docProps/core.xml', $this->getWriterPart('DocProps')->writeDocPropsCore($this->_spreadSheet)); + $customPropertiesPart = $this->getWriterPart('DocProps')->writeDocPropsCustom($this->_spreadSheet); + if ($customPropertiesPart !== NULL) { + $objZip->addFromString('docProps/custom.xml', $customPropertiesPart); + } // Add theme to ZIP file $objZip->addFromString('xl/theme/theme1.xml', $this->getWriterPart('Theme')->writeTheme($this->_spreadSheet)); @@ -359,7 +365,7 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter * @throws Exception */ public function getPHPExcel() { - if (!is_null($this->_spreadSheet)) { + if ($this->_spreadSheet !== null) { return $this->_spreadSheet; } else { throw new Exception("No PHPExcel assigned."); @@ -499,7 +505,7 @@ class PHPExcel_Writer_Excel2007 implements PHPExcel_Writer_IWriter public function setUseDiskCaching($pValue = false, $pDirectory = null) { $this->_useDiskCaching = $pValue; - if (!is_null($pDirectory)) { + if ($pDirectory !== NULL) { if (is_dir($pDirectory)) { $this->_diskCachingDirectory = $pDirectory; } else { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Comments.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Comments.php index 3a6ad37ce..2b758c2a9 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Comments.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Comments.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_Comments extends PHPExcel_Writer_Excel2007_WriterPart { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/ContentTypes.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/ContentTypes.php index 84de96d5d..0b3191bb1 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/ContentTypes.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/ContentTypes.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_ContentTypes extends PHPExcel_Writer_Excel2007_WriterPart { @@ -98,6 +98,13 @@ class PHPExcel_Writer_Excel2007_ContentTypes extends PHPExcel_Writer_Excel2007_W $objWriter, '/docProps/core.xml', 'application/vnd.openxmlformats-package.core-properties+xml' ); + $customPropertyList = $pPHPExcel->getProperties()->getCustomProperties(); + if (count($customPropertyList) > 0) { + $this->_writeOverrideContentType( + $objWriter, '/docProps/custom.xml', 'application/vnd.openxmlformats-officedocument.custom-properties+xml' + ); + } + // Worksheets $sheetCount = $pPHPExcel->getSheetCount(); for ($i = 0; $i < $sheetCount; ++$i) { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/DocProps.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/DocProps.php index 21fc3a4ad..f6c6bbcd6 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/DocProps.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/DocProps.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_WriterPart { @@ -57,8 +57,8 @@ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_Write // Properties $objWriter->startElement('Properties'); - $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'); - $objWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); + $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'); + $objWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); // Application $objWriter->writeElement('Application', 'Microsoft Excel'); @@ -74,9 +74,8 @@ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_Write // Vector $objWriter->startElement('vt:vector'); - $objWriter->writeAttribute('size', '2'); - $objWriter->writeAttribute('baseType', 'variant'); - + $objWriter->writeAttribute('size', '2'); + $objWriter->writeAttribute('baseType', 'variant'); // Variant $objWriter->startElement('vt:variant'); @@ -97,13 +96,13 @@ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_Write // Vector $objWriter->startElement('vt:vector'); - $objWriter->writeAttribute('size', $pPHPExcel->getSheetCount()); - $objWriter->writeAttribute('baseType', 'lpstr'); + $objWriter->writeAttribute('size', $pPHPExcel->getSheetCount()); + $objWriter->writeAttribute('baseType', 'lpstr'); - $sheetCount = $pPHPExcel->getSheetCount(); - for ($i = 0; $i < $sheetCount; ++$i) { - $objWriter->writeElement('vt:lpstr', $pPHPExcel->getSheet($i)->getTitle()); - } + $sheetCount = $pPHPExcel->getSheetCount(); + for ($i = 0; $i < $sheetCount; ++$i) { + $objWriter->writeElement('vt:lpstr', $pPHPExcel->getSheet($i)->getTitle()); + } $objWriter->endElement(); @@ -112,6 +111,9 @@ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_Write // Company $objWriter->writeElement('Company', $pPHPExcel->getProperties()->getCompany()); + // Company + $objWriter->writeElement('Manager', $pPHPExcel->getProperties()->getManager()); + // LinksUpToDate $objWriter->writeElement('LinksUpToDate', 'false'); @@ -152,11 +154,11 @@ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_Write // cp:coreProperties $objWriter->startElement('cp:coreProperties'); - $objWriter->writeAttribute('xmlns:cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties'); - $objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); - $objWriter->writeAttribute('xmlns:dcterms', 'http://purl.org/dc/terms/'); - $objWriter->writeAttribute('xmlns:dcmitype', 'http://purl.org/dc/dcmitype/'); - $objWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $objWriter->writeAttribute('xmlns:cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties'); + $objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $objWriter->writeAttribute('xmlns:dcterms', 'http://purl.org/dc/terms/'); + $objWriter->writeAttribute('xmlns:dcmitype', 'http://purl.org/dc/dcmitype/'); + $objWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); // dc:creator $objWriter->writeElement('dc:creator', $pPHPExcel->getProperties()->getCreator()); @@ -166,14 +168,14 @@ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_Write // dcterms:created $objWriter->startElement('dcterms:created'); - $objWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); - $objWriter->writeRaw(date(DATE_W3C, $pPHPExcel->getProperties()->getCreated())); + $objWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); + $objWriter->writeRawData(date(DATE_W3C, $pPHPExcel->getProperties()->getCreated())); $objWriter->endElement(); // dcterms:modified $objWriter->startElement('dcterms:modified'); - $objWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); - $objWriter->writeRaw(date(DATE_W3C, $pPHPExcel->getProperties()->getModified())); + $objWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); + $objWriter->writeRawData(date(DATE_W3C, $pPHPExcel->getProperties()->getModified())); $objWriter->endElement(); // dc:title @@ -196,4 +198,75 @@ class PHPExcel_Writer_Excel2007_DocProps extends PHPExcel_Writer_Excel2007_Write // Return return $objWriter->getData(); } + + /** + * Write docProps/custom.xml to XML format + * + * @param PHPExcel $pPHPExcel + * @return string XML Output + * @throws Exception + */ + public function writeDocPropsCustom(PHPExcel $pPHPExcel = null) + { + $customPropertyList = $pPHPExcel->getProperties()->getCustomProperties(); + if (count($customPropertyList) == 0) { + return; + } + + // Create XML writer + $objWriter = null; + if ($this->getParentWriter()->getUseDiskCaching()) { + $objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + } else { + $objWriter = new PHPExcel_Shared_XMLWriter(PHPExcel_Shared_XMLWriter::STORAGE_MEMORY); + } + + // XML header + $objWriter->startDocument('1.0','UTF-8','yes'); + + // cp:coreProperties + $objWriter->startElement('Properties'); + $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/custom-properties'); + $objWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); + + + foreach($customPropertyList as $key => $customProperty) { + $propertyValue = $pPHPExcel->getProperties()->getCustomPropertyValue($customProperty); + $propertyType = $pPHPExcel->getProperties()->getCustomPropertyType($customProperty); + + $objWriter->startElement('property'); + $objWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}'); + $objWriter->writeAttribute('pid', $key+2); + $objWriter->writeAttribute('name', $customProperty); + + switch($propertyType) { + case 'i' : + $objWriter->writeElement('vt:i4', $propertyValue); + break; + case 'f' : + $objWriter->writeElement('vt:r8', $propertyValue); + break; + case 'b' : + $objWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false'); + break; + case 'd' : + $objWriter->startElement('vt:filetime'); + $objWriter->writeRawData(date(DATE_W3C, $propertyValue)); + $objWriter->endElement(); + break; + default : + $objWriter->writeElement('vt:lpwstr', $propertyValue); + break; + } + + $objWriter->endElement(); + } + + + $objWriter->endElement(); + + // Return + return $objWriter->getData(); + } + } diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Drawing.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Drawing.php index f1551dac9..59b3bfb64 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Drawing.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Drawing.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_Drawing extends PHPExcel_Writer_Excel2007_WriterPart { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Rels.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Rels.php index 7ffdd6daa..fbde8cdc2 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Rels.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Rels.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_Rels extends PHPExcel_Writer_Excel2007_WriterPart { @@ -59,6 +59,18 @@ class PHPExcel_Writer_Excel2007_Rels extends PHPExcel_Writer_Excel2007_WriterPar $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); + $customPropertyList = $pPHPExcel->getProperties()->getCustomProperties(); + if (count($customPropertyList) > 0) { + // Relationship docProps/app.xml + $this->_writeRelationship( + $objWriter, + 4, + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties', + 'docProps/custom.xml' + ); + + } + // Relationship docProps/app.xml $this->_writeRelationship( $objWriter, diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/StringTable.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/StringTable.php index 98a3c45d4..2e71c67d1 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/StringTable.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/StringTable.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_StringTable extends PHPExcel_Writer_Excel2007_WriterPart { @@ -59,24 +59,22 @@ class PHPExcel_Writer_Excel2007_StringTable extends PHPExcel_Writer_Excel2007_Wr // Fill index array $aFlippedStringTable = $this->flipStringTable($aStringTable); - // Loop through cells - foreach ($pSheet->getCellCollection() as $cellID) { + // Loop through cells + foreach ($pSheet->getCellCollection() as $cellID) { $cell = $pSheet->getCell($cellID); - if (!is_object($cell->getValue()) && - !isset($aFlippedStringTable[$cell->getValue()]) && - !is_null($cell->getValue()) && - $cell->getValue() !== '' && - ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_STRING || $cell->getDataType() == PHPExcel_Cell_DataType::TYPE_NULL) - ) { - $aStringTable[] = $cell->getValue(); - $aFlippedStringTable[$cell->getValue()] = 1; - - } else if ($cell->getValue() instanceof PHPExcel_RichText && - !isset($aFlippedStringTable[$cell->getValue()->getHashCode()]) && - !is_null($cell->getValue()) - ) { - $aStringTable[] = $cell->getValue(); - $aFlippedStringTable[$cell->getValue()->getHashCode()] = 1; + $cellValue = $cell->getValue(); + if (!is_object($cellValue) && + !is_null($cellValue) && + $cellValue !== '' && + !isset($aFlippedStringTable[$cellValue]) && + ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_STRING || $cell->getDataType() == PHPExcel_Cell_DataType::TYPE_STRING2 || $cell->getDataType() == PHPExcel_Cell_DataType::TYPE_NULL)) { + $aStringTable[] = $cellValue; + $aFlippedStringTable[$cellValue] = 1; + } elseif ($cellValue instanceof PHPExcel_RichText && + !is_null($cellValue) && + !isset($aFlippedStringTable[$cellValue->getHashCode()])) { + $aStringTable[] = $cellValue; + $aFlippedStringTable[$cellValue->getHashCode()] = 1; } } @@ -123,7 +121,7 @@ class PHPExcel_Writer_Excel2007_StringTable extends PHPExcel_Writer_Excel2007_Wr if ($textToWrite !== trim($textToWrite)) { $objWriter->writeAttribute('xml:space', 'preserve'); } - $objWriter->writeRaw($textToWrite); + $objWriter->writeRawData($textToWrite); $objWriter->endElement(); } else if ($textElement instanceof PHPExcel_RichText) { $this->writeRichText($objWriter, $textElement); @@ -213,7 +211,7 @@ class PHPExcel_Writer_Excel2007_StringTable extends PHPExcel_Writer_Excel2007_Wr // t $objWriter->startElement('t'); $objWriter->writeAttribute('xml:space', 'preserve'); - $objWriter->writeRaw(PHPExcel_Shared_String::ControlCharacterPHP2OOXML( $element->getText() )); + $objWriter->writeRawData(PHPExcel_Shared_String::ControlCharacterPHP2OOXML( $element->getText() )); $objWriter->endElement(); $objWriter->endElement(); diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Style.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Style.php index 5354936ac..2cdc89adc 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Style.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Style.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_Style extends PHPExcel_Writer_Excel2007_WriterPart { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Theme.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Theme.php index e8ffe7b2d..7af5a939b 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Theme.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Theme.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_Theme extends PHPExcel_Writer_Excel2007_WriterPart { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Workbook.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Workbook.php index d2c51fbc4..6bc8b5a75 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Workbook.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Workbook.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_Workbook extends PHPExcel_Writer_Excel2007_WriterPart { @@ -321,14 +321,14 @@ class PHPExcel_Writer_Excel2007_Workbook extends PHPExcel_Writer_Excel2007_Write // Create absolute coordinate and write as raw text $range = PHPExcel_Cell::splitRange($pNamedRange->getRange()); for ($i = 0; $i < count($range); $i++) { - $range[$i][0] = '\'' . str_replace("'", "''", $pNamedRange->getWorksheet()->getTitle()) . '\'!' . PHPExcel_Cell::absoluteCoordinate($range[$i][0]); + $range[$i][0] = '\'' . str_replace("'", "''", $pNamedRange->getWorksheet()->getTitle()) . '\'!' . PHPExcel_Cell::absoluteReference($range[$i][0]); if (isset($range[$i][1])) { - $range[$i][1] = PHPExcel_Cell::absoluteCoordinate($range[$i][1]); + $range[$i][1] = PHPExcel_Cell::absoluteReference($range[$i][1]); } } $range = PHPExcel_Cell::buildRange($range); - $objWriter->writeRaw($range); + $objWriter->writeRawData($range); $objWriter->endElement(); } @@ -357,7 +357,7 @@ class PHPExcel_Writer_Excel2007_Workbook extends PHPExcel_Writer_Excel2007_Write $range[1] = PHPExcel_Cell::absoluteCoordinate($range[1]); $range = implode(':', $range); - $objWriter->writeRaw('\'' . str_replace("'", "''", $pSheet->getTitle()) . '\'!' . $range); + $objWriter->writeRawData('\'' . str_replace("'", "''", $pSheet->getTitle()) . '\'!' . $range); $objWriter->endElement(); } @@ -400,7 +400,7 @@ class PHPExcel_Writer_Excel2007_Workbook extends PHPExcel_Writer_Excel2007_Write $settingString .= '\'' . str_replace("'", "''", $pSheet->getTitle()) . '\'!$' . $repeat[0] . ':$' . $repeat[1]; } - $objWriter->writeRaw($settingString); + $objWriter->writeRawData($settingString); $objWriter->endElement(); } @@ -430,12 +430,12 @@ class PHPExcel_Writer_Excel2007_Workbook extends PHPExcel_Writer_Excel2007_Write $chunks = array(); foreach ($printArea as $printAreaRect) { - $printAreaRect[0] = PHPExcel_Cell::absoluteCoordinate($printAreaRect[0]); - $printAreaRect[1] = PHPExcel_Cell::absoluteCoordinate($printAreaRect[1]); + $printAreaRect[0] = PHPExcel_Cell::absoluteReference($printAreaRect[0]); + $printAreaRect[1] = PHPExcel_Cell::absoluteReference($printAreaRect[1]); $chunks[] = '\'' . str_replace("'", "''", $pSheet->getTitle()) . '\'!' . implode(':', $printAreaRect); } - $objWriter->writeRaw(implode(',', $chunks)); + $objWriter->writeRawData(implode(',', $chunks)); $objWriter->endElement(); } diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Worksheet.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Worksheet.php index 327e542eb..a84b07524 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Worksheet.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/Worksheet.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_WriterPart { @@ -198,10 +198,10 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ // sheetViews $objWriter->startElement('sheetViews'); - // Sheet selected? - $sheetSelected = false; - if ($this->getParentWriter()->getPHPExcel()->getIndex($pSheet) == $this->getParentWriter()->getPHPExcel()->getActiveSheetIndex()) - $sheetSelected = true; + // Sheet selected? + $sheetSelected = false; + if ($this->getParentWriter()->getPHPExcel()->getIndex($pSheet) == $this->getParentWriter()->getPHPExcel()->getActiveSheetIndex()) + $sheetSelected = true; // sheetView @@ -209,13 +209,13 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0'); $objWriter->writeAttribute('workbookViewId', '0'); - // Zoom scales - if ($pSheet->getSheetView()->getZoomScale() != 100) { - $objWriter->writeAttribute('zoomScale', $pSheet->getSheetView()->getZoomScale()); - } - if ($pSheet->getSheetView()->getZoomScaleNormal() != 100) { - $objWriter->writeAttribute('zoomScaleNormal', $pSheet->getSheetView()->getZoomScaleNormal()); - } + // Zoom scales + if ($pSheet->getSheetView()->getZoomScale() != 100) { + $objWriter->writeAttribute('zoomScale', $pSheet->getSheetView()->getZoomScale()); + } + if ($pSheet->getSheetView()->getZoomScaleNormal() != 100) { + $objWriter->writeAttribute('zoomScaleNormal', $pSheet->getSheetView()->getZoomScaleNormal()); + } // Gridlines if ($pSheet->getShowGridlines()) { @@ -236,31 +236,50 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->writeAttribute('rightToLeft', 'true'); } - // Pane - if ($pSheet->getFreezePane() != '') { - // Calculate freeze coordinates - $xSplit = 0; - $ySplit = 0; - $topLeftCell = $pSheet->getFreezePane(); + $activeCell = $pSheet->getActiveCell(); - list($xSplit, $ySplit) = PHPExcel_Cell::coordinateFromString($pSheet->getFreezePane()); + // Pane + $pane = ''; + $topLeftCell = $pSheet->getFreezePane(); + if (($topLeftCell != '') && ($topLeftCell != 'A1')) { + $activeCell = $topLeftCell; + // Calculate freeze coordinates + $xSplit = $ySplit = 0; + + list($xSplit, $ySplit) = PHPExcel_Cell::coordinateFromString($topLeftCell); $xSplit = PHPExcel_Cell::columnIndexFromString($xSplit); // pane + $pane = 'topRight'; $objWriter->startElement('pane'); - $objWriter->writeAttribute('xSplit', $xSplit - 1); - $objWriter->writeAttribute('ySplit', $ySplit - 1); + if ($xSplit > 1) + $objWriter->writeAttribute('xSplit', $xSplit - 1); + if ($ySplit > 1) { + $objWriter->writeAttribute('ySplit', $ySplit - 1); + $pane = ($xSplit > 1) ? 'bottomRight' : 'bottomLeft'; + } $objWriter->writeAttribute('topLeftCell', $topLeftCell); - $objWriter->writeAttribute('activePane', 'bottomRight'); + $objWriter->writeAttribute('activePane', $pane); $objWriter->writeAttribute('state', 'frozen'); $objWriter->endElement(); + + if (($xSplit > 1) && ($ySplit > 1)) { + // Write additional selections if more than two panes (ie both an X and a Y split) + $objWriter->startElement('selection'); $objWriter->writeAttribute('pane', 'topRight'); $objWriter->endElement(); + $objWriter->startElement('selection'); $objWriter->writeAttribute('pane', 'bottomLeft'); $objWriter->endElement(); + } } // Selection - $objWriter->startElement('selection'); - $objWriter->writeAttribute('activeCell', $pSheet->getActiveCell()); - $objWriter->writeAttribute('sqref', $pSheet->getSelectedCells()); - $objWriter->endElement(); + if ($pane != '') { + // Only need to write selection element if we have a split pane + // We cheat a little by over-riding the active cell selection, setting it to the split cell + $objWriter->startElement('selection'); + $objWriter->writeAttribute('pane', $pane); + $objWriter->writeAttribute('activeCell', $activeCell); + $objWriter->writeAttribute('sqref', $activeCell); + $objWriter->endElement(); + } $objWriter->endElement(); @@ -282,14 +301,14 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ // Default row height if ($pSheet->getDefaultRowDimension()->getRowHeight() >= 0) { $objWriter->writeAttribute('customHeight', 'true'); - $objWriter->writeAttribute('defaultRowHeight', PHPExcel_Shared_String::FormatNumber($pSheet->getDefaultRowDimension()->getRowHeight())); + $objWriter->writeAttribute('defaultRowHeight', PHPExcel_Shared_String::FormatNumber($pSheet->getDefaultRowDimension()->getRowHeight())); } else { - $objWriter->writeAttribute('defaultRowHeight', '12.75'); + $objWriter->writeAttribute('defaultRowHeight', '12.75'); } // Default column width if ($pSheet->getDefaultColumnDimension()->getWidth() >= 0) { - $objWriter->writeAttribute('defaultColWidth', PHPExcel_Shared_String::FormatNumber($pSheet->getDefaultColumnDimension()->getWidth())); + $objWriter->writeAttribute('defaultColWidth', PHPExcel_Shared_String::FormatNumber($pSheet->getDefaultColumnDimension()->getWidth())); } // Outline level - row @@ -299,7 +318,7 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $outlineLevelRow = $dimension->getOutlineLevel(); } } - $objWriter->writeAttribute('outlineLevelRow', (int)$outlineLevelRow); + $objWriter->writeAttribute('outlineLevelRow', (int)$outlineLevelRow); // Outline level - column $outlineLevelCol = 0; @@ -308,7 +327,7 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $outlineLevelCol = $dimension->getOutlineLevel(); } } - $objWriter->writeAttribute('outlineLevelCol', (int)$outlineLevelCol); + $objWriter->writeAttribute('outlineLevelCol', (int)$outlineLevelCol); $objWriter->endElement(); } @@ -456,23 +475,23 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->writeAttribute('text', $conditional->getText()); } - if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT - && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_CONTAINSTEXT - && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))'); - } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT - && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_BEGINSWITH - && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); - } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT - && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_ENDSWITH - && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); - } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT - && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_NOTCONTAINS - && !is_null($conditional->getText())) { - $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))'); - } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CELLIS + if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT + && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_CONTAINSTEXT + && !is_null($conditional->getText())) { + $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))'); + } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT + && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_BEGINSWITH + && !is_null($conditional->getText())) { + $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); + } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT + && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_ENDSWITH + && !is_null($conditional->getText())) { + $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"'); + } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT + && $conditional->getOperatorType() == PHPExcel_Style_Conditional::OPERATOR_NOTCONTAINS + && !is_null($conditional->getText())) { + $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))'); + } else if ($conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CELLIS || $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT || $conditional->getConditionType() == PHPExcel_Style_Conditional::CONDITION_EXPRESSION) { foreach ($conditional->getConditions() as $formula) { @@ -726,20 +745,20 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $objWriter->writeAttribute('orientation', $pSheet->getPageSetup()->getOrientation()); if (!is_null($pSheet->getPageSetup()->getScale())) { - $objWriter->writeAttribute('scale', $pSheet->getPageSetup()->getScale()); + $objWriter->writeAttribute('scale', $pSheet->getPageSetup()->getScale()); } if (!is_null($pSheet->getPageSetup()->getFitToHeight())) { - $objWriter->writeAttribute('fitToHeight', $pSheet->getPageSetup()->getFitToHeight()); + $objWriter->writeAttribute('fitToHeight', $pSheet->getPageSetup()->getFitToHeight()); } else { - $objWriter->writeAttribute('fitToHeight', '0'); + $objWriter->writeAttribute('fitToHeight', '0'); } if (!is_null($pSheet->getPageSetup()->getFitToWidth())) { - $objWriter->writeAttribute('fitToWidth', $pSheet->getPageSetup()->getFitToWidth()); + $objWriter->writeAttribute('fitToWidth', $pSheet->getPageSetup()->getFitToWidth()); } else { - $objWriter->writeAttribute('fitToWidth', '0'); + $objWriter->writeAttribute('fitToWidth', '0'); } if (!is_null($pSheet->getPageSetup()->getFirstPageNumber())) { - $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber()); + $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber()); $objWriter->writeAttribute('useFirstPageNumber', '1'); } @@ -858,12 +877,13 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ $cellsByRow[$cellAddress[1]][] = $cellID; } - for ($currentRow = 1; $currentRow <= $highestRow; ++$currentRow) { + $currentRow = 0; + while($currentRow++ < $highestRow) { // Get row dimension $rowDimension = $pSheet->getRowDimension($currentRow); // Write current row? - $writeCurrentRow = isset($cellsByRow[$currentRow]) || + $writeCurrentRow = isset($cellsByRow[$currentRow]) || $rowDimension->getRowHeight() >= 0 || $rowDimension->getVisible() == false || $rowDimension->getCollapsed() == true || @@ -934,12 +954,11 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ */ private function _writeCell(PHPExcel_Shared_XMLWriter $objWriter = null, PHPExcel_Worksheet $pSheet = null, $pCellAddress = null, $pStringTable = null, $pFlippedStringTable = null) { - $pCell = $pSheet->getCell($pCellAddress); - if (is_array($pStringTable) && is_array($pFlippedStringTable)) { // Cell + $pCell = $pSheet->getCell($pCellAddress); $objWriter->startElement('c'); - $objWriter->writeAttribute('r', $pCell->getCoordinate()); + $objWriter->writeAttribute('r', $pCellAddress); // Sheet styles if ($pCell->getXfIndex() != '') { @@ -947,29 +966,24 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ } // If cell value is supplied, write cell value - if (is_object($pCell->getValue()) || $pCell->getValue() !== '') { + $cellValue = $pCell->getValue(); + if (is_object($cellValue) || $cellValue !== '') { // Map type $mappedType = $pCell->getDataType(); // Write data type depending on its type switch (strtolower($mappedType)) { case 'inlinestr': // Inline string - $objWriter->writeAttribute('t', $mappedType); - break; case 's': // String - $objWriter->writeAttribute('t', $mappedType); - break; case 'b': // Boolean $objWriter->writeAttribute('t', $mappedType); break; case 'f': // Formula $calculatedValue = null; if ($this->getParentWriter()->getPreCalculateFormulas()) { - $pCell->attach($pSheet); $calculatedValue = $pCell->getCalculatedValue(); } else { - $pCell->attach($pSheet); - $calculatedValue = $pCell->getValue(); + $calculatedValue = $cellValue; } if (is_string($calculatedValue)) { $objWriter->writeAttribute('t', 'str'); @@ -982,22 +996,22 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ // Write data depending on its type switch (strtolower($mappedType)) { case 'inlinestr': // Inline string - if (! $pCell->getValue() instanceof PHPExcel_RichText) { - $objWriter->writeElement('t', PHPExcel_Shared_String::ControlCharacterPHP2OOXML( htmlspecialchars($pCell->getValue()) ) ); - } else if ($pCell->getValue() instanceof PHPExcel_RichText) { + if (! $cellValue instanceof PHPExcel_RichText) { + $objWriter->writeElement('t', PHPExcel_Shared_String::ControlCharacterPHP2OOXML( htmlspecialchars($cellValue) ) ); + } else if ($cellValue instanceof PHPExcel_RichText) { $objWriter->startElement('is'); - $this->getParentWriter()->getWriterPart('stringtable')->writeRichText($objWriter, $pCell->getValue()); + $this->getParentWriter()->getWriterPart('stringtable')->writeRichText($objWriter, $cellValue); $objWriter->endElement(); } break; case 's': // String - if (! $pCell->getValue() instanceof PHPExcel_RichText) { - if (isset($pFlippedStringTable[$pCell->getValue()])) { - $objWriter->writeElement('v', $pFlippedStringTable[$pCell->getValue()]); + if (! $cellValue instanceof PHPExcel_RichText) { + if (isset($pFlippedStringTable[$cellValue])) { + $objWriter->writeElement('v', $pFlippedStringTable[$cellValue]); } - } else if ($pCell->getValue() instanceof PHPExcel_RichText) { - $objWriter->writeElement('v', $pFlippedStringTable[$pCell->getValue()->getHashCode()]); + } else if ($cellValue instanceof PHPExcel_RichText) { + $objWriter->writeElement('v', $pFlippedStringTable[$cellValue->getHashCode()]); } break; @@ -1006,20 +1020,19 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ if($attributes['t'] == 'array') { $objWriter->startElement('f'); $objWriter->writeAttribute('t', 'array'); - $objWriter->writeAttribute('ref', $pCell->getCoordinate()); + $objWriter->writeAttribute('ref', $pCellAddress); $objWriter->writeAttribute('aca', '1'); $objWriter->writeAttribute('ca', '1'); - $objWriter->text(substr($pCell->getValue(), 1)); + $objWriter->text(substr($cellValue, 1)); $objWriter->endElement(); } else { - $objWriter->writeElement('f', substr($pCell->getValue(), 1)); + $objWriter->writeElement('f', substr($cellValue, 1)); } if ($this->getParentWriter()->getOffice2003Compatibility() === false) { if ($this->getParentWriter()->getPreCalculateFormulas()) { $calculatedValue = $pCell->getCalculatedValue(); if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') { - $v = PHPExcel_Shared_String::FormatNumber($calculatedValue); - $objWriter->writeElement('v', $v); + $objWriter->writeElement('v', PHPExcel_Shared_String::FormatNumber($calculatedValue)); } else { $objWriter->writeElement('v', '0'); } @@ -1030,18 +1043,17 @@ class PHPExcel_Writer_Excel2007_Worksheet extends PHPExcel_Writer_Excel2007_Writ break; case 'n': // Numeric // force point as decimal separator in case current locale uses comma - $v = str_replace(',', '.', $pCell->getValue()); - $objWriter->writeElement('v', $v); + $objWriter->writeElement('v', str_replace(',', '.', $cellValue)); break; case 'b': // Boolean - $objWriter->writeElement('v', ($pCell->getValue() ? '1' : '0')); + $objWriter->writeElement('v', ($cellValue ? '1' : '0')); break; case 'e': // Error - if (substr($pCell->getValue(), 0, 1) == '=') { - $objWriter->writeElement('f', substr($pCell->getValue(), 1)); - $objWriter->writeElement('v', substr($pCell->getValue(), 1)); + if (substr($cellValue, 0, 1) == '=') { + $objWriter->writeElement('f', substr($cellValue, 1)); + $objWriter->writeElement('v', substr($cellValue, 1)); } else { - $objWriter->writeElement('v', $pCell->getValue()); + $objWriter->writeElement('v', $cellValue); } break; diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/WriterPart.php b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/WriterPart.php index 97d56e109..638cbb62c 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel2007/WriterPart.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel2007/WriterPart.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel2007 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ abstract class PHPExcel_Writer_Excel2007_WriterPart { @@ -65,4 +65,17 @@ abstract class PHPExcel_Writer_Excel2007_WriterPart throw new Exception("No parent PHPExcel_Writer_IWriter assigned."); } } + + /** + * Set parent IWriter object + * + * @param PHPExcel_Writer_IWriter $pWriter + * @throws Exception + */ + public function __construct(PHPExcel_Writer_IWriter $pWriter = null) { + if (!is_null($pWriter)) { + $this->_parentWriter = $pWriter; + } + } + } diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5.php index 4d69d91ff..f69bc4d5c 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter { @@ -40,7 +40,7 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter * * @var boolean */ - private $_preCalculateFormulas; + private $_preCalculateFormulas = true; /** * PHPExcel object @@ -54,28 +54,28 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter * * @var integer */ - private $_BIFF_version; + private $_BIFF_version = 0x0600; /** * Total number of shared strings in workbook * * @var int */ - private $_str_total; + private $_str_total = 0; /** * Number of unique shared strings in workbook * * @var int */ - private $_str_unique; + private $_str_unique = 0; /** * Array of unique shared strings in workbook * * @var array */ - private $_str_table; + private $_str_table = array(); /** * Color cache. Mapping between RGB value and color index. @@ -105,15 +105,9 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter * @param PHPExcel $phpExcel PHPExcel object */ public function __construct(PHPExcel $phpExcel) { - $this->_preCalculateFormulas = true; $this->_phpExcel = $phpExcel; - $this->_BIFF_version = 0x0600; - - $this->_str_total = 0; - $this->_str_unique = 0; - $this->_str_table = array(); - $this->_parser = new PHPExcel_Writer_Excel5_Parser($this->_BIFF_version); + $this->_parser = new PHPExcel_Writer_Excel5_Parser($this->_BIFF_version); } /** @@ -395,9 +389,8 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter case 1: // GIF, not supported by BIFF8, we convert to PNG $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG; - $imageResource = imagecreatefromgif($filename); ob_start(); - imagepng($imageResource); + imagepng(imagecreatefromgif($filename)); $blipData = ob_get_contents(); ob_end_clean(); break; @@ -414,9 +407,8 @@ class PHPExcel_Writer_Excel5 implements PHPExcel_Writer_IWriter case 6: // Windows DIB (BMP), we convert to PNG $blipType = PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG; - $imageResource = PHPExcel_Shared_Drawing::imagecreatefrombmp($filename); ob_start(); - imagepng($imageResource); + imagepng(PHPExcel_Shared_Drawing::imagecreatefrombmp($filename)); $blipData = ob_get_contents(); ob_end_clean(); break; diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5/BIFFwriter.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5/BIFFwriter.php index e758aeb20..6ff3c1966 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5/BIFFwriter.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5/BIFFwriter.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ // Original file header of PEAR::Spreadsheet_Excel_Writer_BIFFwriter (used as the base for this class): @@ -32,7 +32,7 @@ // * The majority of this is _NOT_ my code. I simply ported it from the // * PERL Spreadsheet::WriteExcel module. // * -// * The author of the Spreadsheet::WriteExcel module is John McNamara +// * The author of the Spreadsheet::WriteExcel module is John McNamara // * // * // * I _DO_ maintain this code, and John McNamara has nothing to do with the @@ -65,7 +65,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5_BIFFwriter { @@ -148,8 +148,8 @@ class PHPExcel_Writer_Excel5_BIFFwriter if (strlen($data) - 4 > $this->_limit) { $data = $this->_addContinue($data); } - $this->_data = $this->_data.$data; - $this->_datasize += strlen($data); + $this->_data .= $data; + $this->_datasize += strlen($data); } /** @@ -164,7 +164,7 @@ class PHPExcel_Writer_Excel5_BIFFwriter $data = $this->_addContinue($data); } $this->_datasize += strlen($data); - + return $data; } @@ -190,7 +190,7 @@ class PHPExcel_Writer_Excel5_BIFFwriter } elseif ($this->_BIFF_version == 0x0600) { $length = 0x0010; - // by inspection of real files, MS Office Excel 2007 writes the following + // by inspection of real files, MS Office Excel 2007 writes the following $unknown = pack("VV", 0x000100D1, 0x00000406); $build = 0x0DBB; diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Escher.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Escher.php index 3c9c29f8e..aff368282 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Escher.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Escher.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5_Escher { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Font.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Font.php index 29280702b..0da4d20fd 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Font.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Font.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5_Font { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Parser.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Parser.php index eb9891e34..3d7e0f9a8 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Parser.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Parser.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ // Original file header of PEAR::Spreadsheet_Excel_Writer_Parser (used as the base for this class): @@ -55,7 +55,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5_Parser { @@ -510,6 +510,7 @@ class PHPExcel_Writer_Excel5_Parser 'VARPA' => array( 365, -1, 0, 0 ), 'STDEVA' => array( 366, -1, 0, 0 ), 'VARA' => array( 367, -1, 0, 0 ), + 'BAHTTEXT' => array( 368, 1, 0, 0 ), ); } @@ -522,7 +523,7 @@ class PHPExcel_Writer_Excel5_Parser */ function _convert($token) { - if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) { + if (preg_match("/\"([^\"]|\"\"){0,255}\"/", $token)) { return $this->_convertString($token); } elseif (is_numeric($token)) { @@ -556,6 +557,10 @@ class PHPExcel_Writer_Excel5_Parser } elseif (isset($this->ptg[$token])) { return pack("C", $this->ptg[$token]); + // match error codes + } elseif (preg_match("/^#[A-Z0\/]{3,5}[!?]{1}$/", $token) or $token == '#N/A') { + return $this->_convertError($token); + // commented so argument number can be processed correctly. See toReversePolish(). /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token)) { @@ -566,6 +571,7 @@ class PHPExcel_Writer_Excel5_Parser } elseif ($token == 'arg') { return ''; } + // TODO: use real error codes throw new Exception("Unknown token $token"); } @@ -791,6 +797,26 @@ class PHPExcel_Writer_Excel5_Parser return $ptgRef . $ext_ref. $row . $col; } + /** + * Convert an error code to a ptgErr + * + * @access private + * @param mixed $num an error codefor conversion to its ptg value + */ + function _convertError($errorCode) + { + switch ($errorCode) { + case '#NULL!': return pack("C", 0x00); + case '#DIV/0!': return pack("C", 0x07); + case '#VALUE!': return pack("C", 0x0F); + case '#REF!': return pack("C", 0x17); + case '#NAME?': return pack("C", 0x1D); + case '#NUM!': return pack("C", 0x24); + case '#N/A': return pack("C", 0x2A); + } + return pack("C", 0xFF); + } + /** * Convert the sheet name part of an external reference, for example "Sheet1" or * "Sheet1:Sheet2", to a packed structure. @@ -1030,7 +1056,7 @@ class PHPExcel_Writer_Excel5_Parser $col = 0; $col_ref_length = strlen($col_ref); for ($i = 0; $i < $col_ref_length; ++$i) { - $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn); + $col += (ord($col_ref{$i}) - 64) * pow(26, $expn); --$expn; } @@ -1100,27 +1126,20 @@ class PHPExcel_Writer_Excel5_Parser { switch($token) { case "+": - return $token; - break; case "-": - return $token; - break; case "*": - return $token; - break; case "/": - return $token; - break; case "(": - return $token; - break; case ")": - return $token; - break; case ",": - return $token; - break; case ";": + case ">=": + case "<=": + case "=": + case "<>": + case "^": + case "&": + case "%": return $token; break; case ">": @@ -1136,21 +1155,6 @@ class PHPExcel_Writer_Excel5_Parser } return $token; break; - case ">=": - return $token; - break; - case "<=": - return $token; - break; - case "=": - return $token; - break; - case "<>": - return $token; - break; - case "^": - return $token; - break; default: // if it's a reference A1 or $A$1 or $A1 or A$1 if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and @@ -1200,10 +1204,15 @@ class PHPExcel_Writer_Excel5_Parser return $token; } // If it's a string (of maximum 255 characters) - elseif (preg_match("/^\"[^\"]{0,255}\"$/",$token)) + elseif (preg_match("/\"([^\"]|\"\"){0,255}\"/",$token) and $this->_lookahead != '"' and (substr_count($token, '"')%2 == 0)) { return $token; } + // If it's an error code + elseif (preg_match("/^#[A-Z0\/]{3,5}[!?]{1}$/", $token) or $token == '#N/A') + { + return $token; + } // if it's a function call elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$token) and ($this->_lookahead == "(")) { @@ -1265,6 +1274,10 @@ class PHPExcel_Writer_Excel5_Parser $this->_advance(); $result2 = $this->_expression(); $result = $this->_createTree('ptgNE', $result, $result2); + } elseif ($this->_current_token == "&") { + $this->_advance(); + $result2 = $this->_expression(); + $result = $this->_createTree('ptgConcat', $result, $result2); } return $result; } @@ -1273,7 +1286,9 @@ class PHPExcel_Writer_Excel5_Parser * It parses a expression. It assumes the following rule: * Expr -> Term [("+" | "-") Term] * -> "string" - * -> "-" Term + * -> "-" Term : Negative value + * -> "+" Term : Positive value + * -> Error code * * @access private * @return mixed The parsed ptg'd tree on success @@ -1281,16 +1296,25 @@ class PHPExcel_Writer_Excel5_Parser function _expression() { // If it's a string return a string node - if (preg_match("/^\"[^\"]{0,255}\"$/", $this->_current_token)) { - $result = $this->_createTree($this->_current_token, '', ''); + if (preg_match("/\"([^\"]|\"\"){0,255}\"/", $this->_current_token)) { + $tmp = str_replace('""', '"', $this->_current_token); + if (($tmp == '"') || ($tmp == '')) $tmp = '""'; // Trap for "" that has been used for an empty string + $result = $this->_createTree($tmp, '', ''); $this->_advance(); return $result; - } elseif ($this->_current_token == "-") { + // If it's an error code + } elseif (preg_match("/^#[A-Z0\/]{3,5}[!?]{1}$/", $this->_current_token) or $this->_current_token == '#N/A'){ + $result = $this->_createTree($this->_current_token, 'ptgErr', ''); + $this->_advance(); + return $result; + // If it's a negative value + } elseif ($this->_current_token == "-") { // catch "-" Term $this->_advance(); $result2 = $this->_expression(); $result = $this->_createTree('ptgUminus', $result2, ''); return $result; + // If it's a positive value } elseif ($this->_current_token == "+") { // catch "+" Term $this->_advance(); @@ -1430,11 +1454,16 @@ class PHPExcel_Writer_Excel5_Parser $this->_advance(); return $result; } + // If it's a number or a percent elseif (is_numeric($this->_current_token)) { - $result = $this->_createTree($this->_current_token, '', ''); - $this->_advance(); - return $result; + if($this->_lookahead == '%'){ + $result = $this->_createTree('ptgPercent', $this->_current_token, ''); + } else { + $result = $this->_createTree($this->_current_token, '', ''); + } + $this->_advance(); + return $result; } // if it's a function call elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$this->_current_token)) @@ -1542,6 +1571,7 @@ class PHPExcel_Writer_Excel5_Parser if (empty($tree)) { // If it's the first call use _parse_tree $tree = $this->_parse_tree; } + if (is_array($tree['left'])) { $converted_tree = $this->toReversePolish($tree['left']); $polish .= $converted_tree; diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Workbook.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Workbook.php index 6e517e6b2..b0223f8ad 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Workbook.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Workbook.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ // Original file header of PEAR::Spreadsheet_Excel_Writer_Workbook (used as the base for this class): @@ -66,7 +66,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5_Workbook extends PHPExcel_Writer_Excel5_BIFFwriter { diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Worksheet.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Worksheet.php index 0dd2b003b..3fd9628e0 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Worksheet.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Worksheet.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ // Original file header of PEAR::Spreadsheet_Excel_Writer_Worksheet (used as the base for this class): @@ -66,7 +66,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter { @@ -242,26 +242,23 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter $this->_outline_on = 1; // calculate values for DIMENSIONS record - $this->_firstRowIndex = 0; - $this->_lastRowIndex = -1; - $this->_firstColumnIndex = 0; - $this->_lastColumnIndex = -1; - + $col = $row = array(); foreach ($this->_phpSheet->getCellCollection(false) as $cellID) { - preg_match('/^(\w+)(\d+)$/U',$cellID,$matches); - list(,$col,$row) = $matches; - $column = PHPExcel_Cell::columnIndexFromString($col) - 1; - - // Don't break Excel! - if ($row + 1 > 65536 or $column + 1 > 256) { - break; - } - - $this->_firstRowIndex = min($this->_firstRowIndex, $row); - $this->_lastRowIndex = max($this->_lastRowIndex, $row); - $this->_firstColumnIndex = min($this->_firstColumnIndex, $column); - $this->_lastColumnIndex = max($this->_lastColumnIndex, $column); + list($c,$r) = sscanf($cellID,'%[A-Z]%d'); + $row[$r] = $r; + $col[$c] = strlen($c).$c; } + // Determine lowest and highest column and row + $this->_firstRowIndex = (count($row) > 0) ? min($row) : 1; + $this->_lastRowIndex = (count($row) > 0) ? max($row) : 1; + if ($this->_firstRowIndex > 65535) $this->_firstRowIndex = 65535; + if ($this->_lastRowIndex > 65535) $this->_lastRowIndex = 65535; + + $this->_firstColumnIndex = (count($col) > 0) ? PHPExcel_Cell::columnIndexFromString(substr(min($col),1)) : 1; + $this->_lastColumnIndex = (count($col) > 0) ? PHPExcel_Cell::columnIndexFromString(substr(max($col),1)) : 1; + + if ($this->_firstColumnIndex > 255) $this->_firstColumnIndex = 255; + if ($this->_lastColumnIndex > 255) $this->_lastColumnIndex = 255; $this->_countCellStyleXfs = count($phpSheet->getParent()->getCellStyleXfCollection()); } @@ -293,8 +290,9 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter $this->_phpSheet->calculateColumnWidths(); // Column dimensions + $maxCol = PHPExcel_Cell::columnIndexFromString($this->_phpSheet->getHighestColumn()) -1; $columnDimensions = $this->_phpSheet->getColumnDimensions(); - for ($i = 0; $i < 256; ++$i) { + for ($i = 0; $i <= $maxCol; ++$i) { $hidden = 0; $level = 0; $xfIndex = 15; // there are 15 cell style Xfs @@ -530,14 +528,12 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter $firstCellCoordinates = PHPExcel_Cell::coordinateFromString($firstCell); // e.g. array(0, 1) $lastCellCoordinates = PHPExcel_Cell::coordinateFromString($lastCell); // e.g. array(1, 6) - $data = pack('vvvv', + return(pack('vvvv', $firstCellCoordinates[1] - 1, $lastCellCoordinates[1] - 1, PHPExcel_Cell::columnIndexFromString($firstCellCoordinates[0]) - 1, PHPExcel_Cell::columnIndexFromString($lastCellCoordinates[0]) - 1 - ); - - return $data; + )); } /** @@ -853,8 +849,8 @@ class PHPExcel_Writer_Excel5_Worksheet extends PHPExcel_Writer_Excel5_BIFFwriter $unknown = 0x0000; // Must be zero // Strip the '=' or '@' sign at the beginning of the formula string - if (preg_match("/^=/", $formula)) { - $formula = preg_replace("/(^=)/", "", $formula); + if ($formula{0} == '=') { + $formula = substr($formula,1); } else { // Error handling $this->_writeString($row, $col, 'Unrecognised character for formula'); diff --git a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Xf.php b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Xf.php index 27632f330..6d48e5bfa 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/Excel5/Xf.php +++ b/libraries/PHPExcel/PHPExcel/Writer/Excel5/Xf.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ // Original file header of PEAR::Spreadsheet_Excel_Writer_Format (used as the base for this class): @@ -66,7 +66,7 @@ * * @category PHPExcel * @package PHPExcel_Writer_Excel5 - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_Excel5_Xf { diff --git a/libraries/PHPExcel/PHPExcel/Writer/HTML.php b/libraries/PHPExcel/PHPExcel/Writer/HTML.php index b6667f5bf..3e7a9b15e 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/HTML.php +++ b/libraries/PHPExcel/PHPExcel/Writer/HTML.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * @category PHPExcel - * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @package PHPExcel_Writer + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 1.7.6, 2011-02-27 */ @@ -30,8 +30,8 @@ * PHPExcel_Writer_HTML * * @category PHPExcel - * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @package PHPExcel_Writer + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** @@ -46,7 +46,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { * * @var int */ - private $_sheetIndex; + private $_sheetIndex = 0; /** * Pre-calculate formulas @@ -60,7 +60,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { * * @var string */ - private $_imagesRoot = '.'; + private $_imagesRoot = '.'; /** * Use inline CSS? @@ -95,28 +95,28 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { * * @var boolean */ - private $_spansAreCalculated; + private $_spansAreCalculated = false; /** * Excel cells that should not be written as HTML cells * * @var array */ - private $_isSpannedCell; + private $_isSpannedCell = array(); /** * Excel cells that are upper-left corner in a cell merge * * @var array */ - private $_isBaseCell; + private $_isBaseCell = array(); /** * Excel rows that should not be written as HTML rows * * @var array */ - private $_isSpannedRow; + private $_isSpannedRow = array(); /** * Is the current writer creating PDF? @@ -125,28 +125,28 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { */ protected $_isPdf = false; + /** + * Generate the Navigation block + * + * @var boolean + */ + private $_generateSheetNavigationBlock = true; + /** * Create a new PHPExcel_Writer_HTML * - * @param PHPExcel $phpExcel PHPExcel object + * @param PHPExcel $phpExcel PHPExcel object */ public function __construct(PHPExcel $phpExcel) { $this->_phpExcel = $phpExcel; $this->_defaultFont = $this->_phpExcel->getDefaultStyle()->getFont(); - $this->_sheetIndex = 0; - $this->_imagesRoot = '.'; - - $this->_spansAreCalculated = false; - $this->_isSpannedCell = array(); - $this->_isBaseCell = array(); - $this->_isSpannedRow = array(); } /** * Save PHPExcel to file * - * @param string $pFileName - * @throws Exception + * @param string $pFileName + * @throws Exception */ public function save($pFilename = null) { // garbage collect @@ -161,7 +161,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { $this->buildCSS(!$this->_useInlineCss); // Open file - $fileHandle = fopen($pFilename, 'w'); + $fileHandle = fopen($pFilename, 'wb+'); if ($fileHandle === false) { throw new Exception("Could not open file $pFilename for writing."); } @@ -170,7 +170,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { fwrite($fileHandle, $this->generateHTMLHeader(!$this->_useInlineCss)); // Write navigation (tabs) - if (!$this->_isPdf) { + if ((!$this->_isPdf) && ($this->_generateSheetNavigationBlock)) { fwrite($fileHandle, $this->generateNavigation()); } @@ -192,10 +192,10 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { */ private function _mapVAlign($vAlign) { switch ($vAlign) { - case PHPExcel_Style_Alignment::VERTICAL_BOTTOM: return 'bottom'; - case PHPExcel_Style_Alignment::VERTICAL_TOP: return 'top'; + case PHPExcel_Style_Alignment::VERTICAL_BOTTOM: return 'bottom'; + case PHPExcel_Style_Alignment::VERTICAL_TOP: return 'top'; case PHPExcel_Style_Alignment::VERTICAL_CENTER: - case PHPExcel_Style_Alignment::VERTICAL_JUSTIFY: return 'middle'; + case PHPExcel_Style_Alignment::VERTICAL_JUSTIFY: return 'middle'; default: return 'baseline'; } } @@ -207,11 +207,12 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { */ private function _mapHAlign($hAlign) { switch ($hAlign) { - case PHPExcel_Style_Alignment::HORIZONTAL_GENERAL: return false; - case PHPExcel_Style_Alignment::HORIZONTAL_LEFT: return 'left'; - case PHPExcel_Style_Alignment::HORIZONTAL_RIGHT: return 'right'; - case PHPExcel_Style_Alignment::HORIZONTAL_CENTER: return 'center'; - case PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY: return 'justify'; + case PHPExcel_Style_Alignment::HORIZONTAL_GENERAL: return false; + case PHPExcel_Style_Alignment::HORIZONTAL_LEFT: return 'left'; + case PHPExcel_Style_Alignment::HORIZONTAL_RIGHT: return 'right'; + case PHPExcel_Style_Alignment::HORIZONTAL_CENTER: + case PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS: return 'center'; + case PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY: return 'justify'; default: return false; } } @@ -221,11 +222,20 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { */ private function _mapBorderStyle($borderStyle) { switch ($borderStyle) { - case PHPExcel_Style_Border::BORDER_NONE: return '0px'; - case PHPExcel_Style_Border::BORDER_DASHED: return '1px dashed'; - case PHPExcel_Style_Border::BORDER_DOTTED: return '1px dotted'; - case PHPExcel_Style_Border::BORDER_DOUBLE: return '3px double'; - case PHPExcel_Style_Border::BORDER_THICK: return '2px solid'; + case PHPExcel_Style_Border::BORDER_NONE: return '0px'; + case PHPExcel_Style_Border::BORDER_DASHDOT: return '1px dashed'; + case PHPExcel_Style_Border::BORDER_DASHDOTDOT: return '1px dotted'; + case PHPExcel_Style_Border::BORDER_DASHED: return '1px dashed'; + case PHPExcel_Style_Border::BORDER_DOTTED: return '1px dotted'; + case PHPExcel_Style_Border::BORDER_DOUBLE: return '3px double'; + case PHPExcel_Style_Border::BORDER_HAIR: return '1px solid'; + case PHPExcel_Style_Border::BORDER_MEDIUM: return '2px solid'; + case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT: return '2px dashed'; + case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT: return '2px dotted'; + case PHPExcel_Style_Border::BORDER_MEDIUMDASHED: return '2px dashed'; + case PHPExcel_Style_Border::BORDER_SLANTDASHDOT: return '2px dashed'; + case PHPExcel_Style_Border::BORDER_THICK: return '3px solid'; + case PHPExcel_Style_Border::BORDER_THIN: return '1px solid'; default: return '1px solid'; // map others to thin } } @@ -250,11 +260,32 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { return $this; } + /** + * Get sheet index + * + * @return boolean + */ + public function getGenerateSheetNavigationBlock() { + return $this->_generateSheetNavigationBlock; + } + + /** + * Set sheet index + * + * @param boolean $pValue Flag indicating whether the sheet navigation block should be generated or not + * @return PHPExcel_Writer_HTML + */ + public function setGenerateSheetNavigationBlock($pValue = true) { + $this->_generateSheetNavigationBlock = (bool) $pValue; + return $this; + } + /** * Write all sheets (resets sheetIndex to NULL) */ public function writeAllSheets() { $this->_sheetIndex = null; + return $this; } /** @@ -271,19 +302,18 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { } // Construct HTML - $html = ''; - $html .= '' . "\r\n"; - $html .= '' . "\r\n"; - $html .= '' . "\r\n"; - $html .= ' ' . "\r\n"; - $html .= ' ' . "\r\n"; - $html .= ' ' . htmlspecialchars($this->_phpExcel->getProperties()->getTitle()) . '' . "\r\n"; + $html = '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= ' ' . PHP_EOL; + $html .= ' ' . PHP_EOL; + $html .= ' ' . htmlspecialchars($this->_phpExcel->getProperties()->getTitle()) . '' . PHP_EOL; if ($pIncludeStyles) { $html .= $this->generateStyles(true); } - $html .= ' ' . "\r\n"; - $html .= '' . "\r\n"; - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= ' ' . PHP_EOL; // Return return $html; @@ -323,22 +353,21 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Write table header $html .= $this->_generateTableHeader($sheet); - // Get worksheet dimension - $dimension = explode(':', $sheet->calculateWorksheetDimension()); - $dimension[0] = PHPExcel_Cell::coordinateFromString($dimension[0]); - $dimension[0][0] = PHPExcel_Cell::columnIndexFromString($dimension[0][0]) - 1; - $dimension[1] = PHPExcel_Cell::coordinateFromString($dimension[1]); - $dimension[1][0] = PHPExcel_Cell::columnIndexFromString($dimension[1][0]) - 1; + // Get worksheet dimension + $dimension = explode(':', $sheet->calculateWorksheetDimension()); + $dimension[0] = PHPExcel_Cell::coordinateFromString($dimension[0]); + $dimension[0][0] = PHPExcel_Cell::columnIndexFromString($dimension[0][0]) - 1; + $dimension[1] = PHPExcel_Cell::coordinateFromString($dimension[1]); + $dimension[1][0] = PHPExcel_Cell::columnIndexFromString($dimension[1][0]) - 1; - // row min,max + // row min,max $rowMin = $dimension[0][1]; $rowMax = $dimension[1][1]; // calculate start of , $tbodyStart = $rowMin; - $tbodyEnd = $rowMax; - $theadStart = 0; // default: no - $theadEnd = 0; // default: no + $tbodyEnd = $rowMax; + $theadStart = $theadEnd = 0; // default: no no if ($sheet->getPageSetup()->isRowsToRepeatAtTopSet()) { $rowsToRepeatAtTop = $sheet->getPageSetup()->getRowsToRepeatAtTop(); @@ -351,55 +380,53 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { } // Loop through cells - $rowData = null; - for ($row = $rowMin; $row <= $rowMax; ++$row) { - // Start a new row - $rowData = array(); - - // Loop through columns - for ($column = $dimension[0][0]; $column <= $dimension[1][0]; ++$column) { - // Cell exists? - if ($sheet->cellExistsByColumnAndRow($column, $row)) { - $rowData[$column] = $cell = $sheet->getCellByColumnAndRow($column, $row); - } else { - $rowData[$column] = ''; - } - } - - // ? + $row = $rowMin-1; + while($row++ < $rowMax) { + // ? if ($row == $theadStart) { - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } - // ? + // ? if ($row == $tbodyStart) { - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } // Write row if there are HTML table cells in it if ( !isset($this->_isSpannedRow[$sheet->getParent()->getIndex($sheet)][$row]) ) { + // Start a new rowData + $rowData = array(); + // Loop through columns + $column = $dimension[0][0] - 1; + while($column++ < $dimension[1][0]) { + // Cell exists? + if ($sheet->cellExistsByColumnAndRow($column, $row)) { + $rowData[$column] = $sheet->getCellByColumnAndRow($column, $row); + } else { + $rowData[$column] = ''; + } + } $html .= $this->_generateRow($sheet, $rowData, $row - 1); } - // ? + // ? if ($row == $theadEnd) { - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } - // ? + // ? if ($row == $tbodyEnd) { - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } - } + } // Write table footer $html .= $this->_generateTableFooter(); // Writing PDF? - if ($this->_isPdf) - { + if ($this->_isPdf) { if (is_null($this->_sheetIndex) && $sheetId + 1 < $this->_phpExcel->getSheetCount()) { - $html .= ''; + $html .= '
'; } } @@ -440,14 +467,14 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Loop all sheets $sheetId = 0; - $html .= '' . PHP_EOL; } return $html; @@ -456,7 +483,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** * Generate image tag in cell * - * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet + * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet * @param string $coordinates Cell coordinates * @return string * @throws Exception @@ -487,8 +514,8 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Convert UTF8 data to PCDATA $filename = htmlspecialchars($filename); - $html .= "\r\n"; - $html .= ' ' . "\r\n"; + $html .= PHP_EOL; + $html .= ' ' . PHP_EOL; } } } @@ -518,20 +545,20 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Start styles if ($generateSurroundingHTML) { - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } // Return @@ -567,8 +594,8 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Start styles if ($generateSurroundingHTML) { // html { } - $css['html']['font-family'] = 'Calibri, Arial, Helvetica, sans-serif'; - $css['html']['font-size'] = '11pt'; + $css['html']['font-family'] = 'Calibri, Arial, Helvetica, sans-serif'; + $css['html']['font-size'] = '11pt'; $css['html']['background-color'] = 'white'; } @@ -622,7 +649,8 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // col elements, initialize $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn()) - 1; - for ($column = 0; $column <= $highestColumnIndex; ++$column) { + $column = -1; + while($column++ < $highestColumnIndex) { $this->_columnWidths[$sheetIndex][$column] = 42; // approximation $css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = '42pt'; } @@ -655,7 +683,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { } $css['table.sheet' . $sheetIndex . ' tr']['height'] = $pt_height . 'pt'; if ($rowDimension->getVisible() === false) { - $css['table.sheet' . $sheetIndex . ' tr']['display'] = 'none'; + $css['table.sheet' . $sheetIndex . ' tr']['display'] = 'none'; $css['table.sheet' . $sheetIndex . ' tr']['visibility'] = 'hidden'; } @@ -691,7 +719,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** * Create CSS style * - * @param PHPExcel_Style $pStyle PHPExcel_Style + * @param PHPExcel_Style $pStyle PHPExcel_Style * @return array */ private function _createCSSStyle(PHPExcel_Style $pStyle) { @@ -713,7 +741,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** * Create CSS style (PHPExcel_Style_Alignment) * - * @param PHPExcel_Style_Alignment $pStyle PHPExcel_Style_Alignment + * @param PHPExcel_Style_Alignment $pStyle PHPExcel_Style_Alignment * @return array */ private function _createCSSStyleAlignment(PHPExcel_Style_Alignment $pStyle) { @@ -733,7 +761,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** * Create CSS style (PHPExcel_Style_Font) * - * @param PHPExcel_Style_Font $pStyle PHPExcel_Style_Font + * @param PHPExcel_Style_Font $pStyle PHPExcel_Style_Font * @return array */ private function _createCSSStyleFont(PHPExcel_Style_Font $pStyle) { @@ -766,7 +794,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** * Create CSS style (PHPExcel_Style_Borders) * - * @param PHPExcel_Style_Borders $pStyle PHPExcel_Style_Borders + * @param PHPExcel_Style_Borders $pStyle PHPExcel_Style_Borders * @return array */ private function _createCSSStyleBorders(PHPExcel_Style_Borders $pStyle) { @@ -825,8 +853,8 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { public function generateHTMLFooter() { // Construct HTML $html = ''; - $html .= ' ' . "\r\n"; - $html .= '' . "\r\n"; + $html .= ' ' . PHP_EOL; + $html .= '' . PHP_EOL; // Return return $html; @@ -835,7 +863,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** * Generate table header * - * @param PHPExcel_Worksheet $pSheet The worksheet for the table we are writing + * @param PHPExcel_Worksheet $pSheet The worksheet for the table we are writing * @return string * @throws Exception */ @@ -847,27 +875,28 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { if (!$this->_useInlineCss) { $gridlines = $pSheet->getShowGridLines() ? ' gridlines' : ''; - $html .= ' ' . "\r\n"; + $html .= '
' . PHP_EOL; } else { $style = isset($this->_cssStyles['table']) ? $this->_assembleCSS($this->_cssStyles['table']) : ''; if ($this->_isPdf && $pSheet->getShowGridLines()) { - $html .= '
' . "\r\n"; + $html .= '
' . PHP_EOL; } else { - $html .= '
' . "\r\n"; + $html .= '
' . PHP_EOL; } } // Write elements $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($pSheet->getHighestColumn()) - 1; - for ($i = 0; $i <= $highestColumnIndex; ++$i) { + $i = -1; + while($i++ < $highestColumnIndex) { if (!$this->_useInlineCss) { - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } else { $style = isset($this->_cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) ? $this->_assembleCSS($this->_cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) : ''; - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } } @@ -883,7 +912,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { private function _generateTableFooter() { // Construct HTML $html = ''; - $html .= '
' . "\r\n"; + $html .= ' ' . PHP_EOL; // Return return $html; @@ -892,7 +921,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** * Generate row * - * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet + * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet * @param array $pValues Array containing cells in a row * @param int $pRow Row number (0-based) * @return string @@ -906,7 +935,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Sheet index $sheetIndex = $pSheet->getParent()->getIndex($pSheet); - // TCPDF and breaks + // DomPDF and breaks if ($this->_isPdf && count($pSheet->getBreaks()) > 0) { $breaks = $pSheet->getBreaks(); @@ -916,7 +945,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { $html .= $this->_generateTableFooter(); // insert page break - $html .= ''; + $html .= '
'; // open table again: + etc. $html .= $this->_generateTableHeader($pSheet); @@ -925,12 +954,12 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Write row start if (!$this->_useInlineCss) { - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } else { $style = isset($this->_cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]) ? $this->_assembleCSS($this->_cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]) : ''; - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; } // Write cells @@ -949,7 +978,6 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { } $colSpan = 1; $rowSpan = 1; - $writeCell = true; // Write cell // initialize $cellData = ''; @@ -1003,13 +1031,19 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { array($this, 'formatColor') ); } + if ($pSheet->getParent()->getCellXfByIndex( $cell->getXfIndex() )->getFont()->getSuperScript()) { + $cellData = ''.$cellData.''; + } elseif ($pSheet->getParent()->getCellXfByIndex( $cell->getXfIndex() )->getFont()->getSubScript()) { + $cellData = ''.$cellData.''; + } } - // replace leading spaces on each line with   - $cellData = $this->_convertNbsp($cellData); + // Converts the cell content so that spaces occuring at beginning of each new line are replaced by   + // Example: " Hello\n to the world" is converted to "  Hello\n to the world" + $cellData = preg_replace("/(?m)(?:^|\\G) /", ' ', $cellData); // convert newline "\n" to '
' - $cellData = str_replace("\n", '
', $cellData); + $cellData = nl2br($cellData); // Extend CSS class? if (!$this->_useInlineCss) { @@ -1051,7 +1085,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // Write if ($writeCell) { // Column start - $html .= ' _useInlineCss) { $html .= ' class="' . $cssClass . '"'; } else { @@ -1059,7 +1093,9 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { // We must explicitly write the width of the $width = 0; - for ($i = $colNum; $i < $colNum + $colSpan; ++$i) { + $i = $colNum - 1; + $e = $colNum + $colSpan - 1; + while($i++ < $e) { if (isset($this->_columnWidths[$sheetIndex][$i])) { $width += $this->_columnWidths[$sheetIndex][$i]; } @@ -1091,7 +1127,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { $html .= $cellData; // Column end - $html .= '' . "\r\n"; + $html .= '' . PHP_EOL; } // Next column @@ -1099,7 +1135,7 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { } // Write row end - $html .= ' ' . "\r\n"; + $html .= ' ' . PHP_EOL; // Return return $html; @@ -1125,86 +1161,64 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { return $string; } - /** - * Get Pre-Calculate Formulas - * - * @return boolean - */ - public function getPreCalculateFormulas() { - return $this->_preCalculateFormulas; - } - - /** - * Set Pre-Calculate Formulas - * - * @param boolean $pValue Pre-Calculate Formulas? - * @return PHPExcel_Writer_HTML - */ - public function setPreCalculateFormulas($pValue = true) { - $this->_preCalculateFormulas = $pValue; - return $this; - } - - /** - * Get images root - * - * @return string - */ - public function getImagesRoot() { - return $this->_imagesRoot; - } - - /** - * Set images root - * - * @param string $pValue - * @return PHPExcel_Writer_HTML - */ - public function setImagesRoot($pValue = '.') { - $this->_imagesRoot = $pValue; - return $this; - } - - /** - * Get use inline CSS? - * - * @return boolean - */ - public function getUseInlineCss() { - return $this->_useInlineCss; - } - - /** - * Set use inline CSS? - * - * @param boolean $pValue - * @return PHPExcel_Writer_HTML - */ - public function setUseInlineCss($pValue = false) { - $this->_useInlineCss = $pValue; - return $this; - } + /** + * Get Pre-Calculate Formulas + * + * @return boolean + */ + public function getPreCalculateFormulas() { + return $this->_preCalculateFormulas; + } /** - * Converts a string so that spaces occuring at beginning of each new line are replaced by   - * Example: " Hello\n to the world" is converted to "  Hello\n to the world" + * Set Pre-Calculate Formulas + * + * @param boolean $pValue Pre-Calculate Formulas? + * @return PHPExcel_Writer_HTML + */ + public function setPreCalculateFormulas($pValue = true) { + $this->_preCalculateFormulas = $pValue; + return $this; + } + + /** + * Get images root * - * @param string $pValue * @return string */ - private function _convertNbsp($pValue = '') - { - $explodes = explode("\n", $pValue); - foreach ($explodes as $explode) { - $matches = array(); - if (preg_match('/^( )+/', $explode, $matches)) { - $explode = str_repeat(' ', strlen($matches[0])) . substr($explode, strlen($matches[0])); - } - $implodes[] = $explode; - } + public function getImagesRoot() { + return $this->_imagesRoot; + } - $string = implode("\n", $implodes); - return $string; + /** + * Set images root + * + * @param string $pValue + * @return PHPExcel_Writer_HTML + */ + public function setImagesRoot($pValue = '.') { + $this->_imagesRoot = $pValue; + return $this; + } + + /** + * Get use inline CSS? + * + * @return boolean + */ + public function getUseInlineCss() { + return $this->_useInlineCss; + } + + /** + * Set use inline CSS? + * + * @param boolean $pValue + * @return PHPExcel_Writer_HTML + */ + public function setUseInlineCss($pValue = false) { + $this->_useInlineCss = $pValue; + return $this; } /** @@ -1267,11 +1281,13 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { $lc = PHPExcel_Cell::columnIndexFromString($lc) - 1; // loop through the individual cells in the individual merge - for ($r = $fr; $r <= $lr; ++$r) { + $r = $fr - 1; + while($r++ < $lr) { // also, flag this row as a HTML row that is candidate to be omitted $candidateSpannedRow[$r] = $r; - for ($c = $fc; $c <= $lc; ++$c) { + $c = $fc - 1; + while($c++ < $lc) { if ( !($c == $fc && $r == $fr) ) { // not the upper-left cell (should not be written in HTML) $this->_isSpannedCell[$sheetIndex][$r][$c] = array( @@ -1305,11 +1321,12 @@ class PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { if ( isset($this->_isSpannedRow[$sheetIndex]) ) { foreach ($this->_isSpannedRow[$sheetIndex] as $rowIndex) { $adjustedBaseCells = array(); - for ($c = 0; $c < $countColumns; ++$c) { + $c = -1; + $e = $countColumns - 1; + while($c++ < $e) { $baseCell = $this->_isSpannedCell[$sheetIndex][$rowIndex][$c]['baseCell']; if ( !in_array($baseCell, $adjustedBaseCells) ) { - // subtract rowspan by 1 --$this->_isBaseCell[$sheetIndex][ $baseCell[0] ][ $baseCell[1] ]['rowspan']; $adjustedBaseCells[] = $baseCell; diff --git a/libraries/PHPExcel/PHPExcel/Writer/IWriter.php b/libraries/PHPExcel/PHPExcel/Writer/IWriter.php index 35fd6890c..97fd2cae6 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/IWriter.php +++ b/libraries/PHPExcel/PHPExcel/Writer/IWriter.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -31,7 +31,7 @@ * * @category PHPExcel * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ interface PHPExcel_Writer_IWriter { diff --git a/libraries/PHPExcel/PHPExcel/Writer/PDF.php b/libraries/PHPExcel/PHPExcel/Writer/PDF.php index f5886359b..43bd1283f 100644 --- a/libraries/PHPExcel/PHPExcel/Writer/PDF.php +++ b/libraries/PHPExcel/PHPExcel/Writer/PDF.php @@ -2,7 +2,7 @@ /** * PHPExcel * - * Copyright (c) 2006 - 2010 PHPExcel + * Copyright (c) 2006 - 2011 PHPExcel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ * * @category PHPExcel * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 1.7.4, 2010-08-26 + * @version 1.7.6, 2011-02-27 */ @@ -35,7 +35,7 @@ require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/PDF/tcpdf.php'; * * @category PHPExcel * @package PHPExcel_Writer - * @copyright Copyright (c) 2006 - 2010 PHPExcel (http://www.codeplex.com/PHPExcel) + * @copyright Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel) */ class PHPExcel_Writer_PDF extends PHPExcel_Writer_HTML implements PHPExcel_Writer_IWriter { /** @@ -245,9 +245,11 @@ class PHPExcel_Writer_PDF extends PHPExcel_Writer_HTML implements PHPExcel_Write if (is_null($this->getSheetIndex())) { $orientation = ($this->_phpExcel->getSheet(0)->getPageSetup()->getOrientation() == PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE) ? 'L' : 'P'; $printPaperSize = $this->_phpExcel->getSheet(0)->getPageSetup()->getPaperSize(); + $printMargins = $this->_phpExcel->getSheet(0)->getPageMargins(); } else { $orientation = ($this->_phpExcel->getSheet($this->getSheetIndex())->getPageSetup()->getOrientation() == PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE) ? 'L' : 'P'; $printPaperSize = $this->_phpExcel->getSheet($this->getSheetIndex())->getPageSetup()->getPaperSize(); + $printMargins = $this->_phpExcel->getSheet($this->getSheetIndex())->getPageMargins(); } // Override Page Orientation @@ -267,8 +269,16 @@ class PHPExcel_Writer_PDF extends PHPExcel_Writer_HTML implements PHPExcel_Write // Create PDF $pdf = new TCPDF($orientation, 'pt', $paperSize); + $pdf->setFontSubsetting(false); + // Set margins, converting inches to points (using 72 dpi) + $pdf->SetMargins($printMargins->getLeft() * 72,$printMargins->getTop() * 72,$printMargins->getRight() * 72); + $pdf->SetAutoPageBreak(true,$printMargins->getBottom() * 72); +// $pdf->setHeaderMargin($printMargins->getHeader() * 72); +// $pdf->setFooterMargin($printMargins->getFooter() * 72); + $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); + $pdf->AddPage(); // Set the appropriate font diff --git a/libraries/PHPExcel/PHPExcel/Writer/Serialized.php b/libraries/PHPExcel/PHPExcel/Writer/Serialized.php deleted file mode 100644 index 51616b44d..000000000 --- a/libraries/PHPExcel/PHPExcel/Writer/Serialized.php +++ /dev/null @@ -1,181 +0,0 @@ -setPHPExcel($pPHPExcel); - } - - /** - * Save PHPExcel to file - * - * @param string $pFileName - * @throws Exception - */ - public function save($pFilename = null) - { - if (!is_null($this->_spreadSheet)) { - // Garbage collect - $this->_spreadSheet->garbageCollect(); - - // Garbage collect... - foreach ($this->_spreadSheet->getAllSheets() as $sheet) { - $sheet->garbageCollect(); - } - - // Create new ZIP file and open it for writing - $objZip = new ZipArchive(); - - // Try opening the ZIP file - if ($objZip->open($pFilename, ZIPARCHIVE::OVERWRITE) !== true) { - if ($objZip->open($pFilename, ZIPARCHIVE::CREATE) !== true) { - throw new Exception("Could not open " . $pFilename . " for writing."); - } - } - - // Add media - $sheetCount = $this->_spreadSheet->getSheetCount(); - for ($i = 0; $i < $sheetCount; ++$i) { - for ($j = 0; $j < $this->_spreadSheet->getSheet($i)->getDrawingCollection()->count(); ++$j) { - if ($this->_spreadSheet->getSheet($i)->getDrawingCollection()->offsetGet($j) instanceof PHPExcel_Worksheet_BaseDrawing) { - $imgTemp = $this->_spreadSheet->getSheet($i)->getDrawingCollection()->offsetGet($j); - $objZip->addFromString('media/' . $imgTemp->getFilename(), file_get_contents($imgTemp->getPath())); - } - } - } - - // Add phpexcel.xml to the document, which represents a PHP serialized PHPExcel object - $objZip->addFromString('phpexcel.xml', $this->_writeSerialized($this->_spreadSheet, $pFilename)); - - // Close file - if ($objZip->close() === false) { - throw new Exception("Could not close zip file $pFilename."); - } - } else { - throw new Exception("PHPExcel object unassigned."); - } - } - - /** - * Get PHPExcel object - * - * @return PHPExcel - * @throws Exception - */ - public function getPHPExcel() { - if (!is_null($this->_spreadSheet)) { - return $this->_spreadSheet; - } else { - throw new Exception("No PHPExcel assigned."); - } - } - - /** - * Get PHPExcel object - * - * @param PHPExcel $pPHPExcel PHPExcel object - * @throws Exception - * @return PHPExcel_Writer_Serialized - */ - public function setPHPExcel(PHPExcel $pPHPExcel = null) { - $this->_spreadSheet = $pPHPExcel; - return $this; - } - - /** - * Serialize PHPExcel object to XML - * - * @param PHPExcel $pPHPExcel - * @param string $pFilename - * @return string XML Output - * @throws Exception - */ - private function _writeSerialized(PHPExcel $pPHPExcel = null, $pFilename = '') - { - // Clone $pPHPExcel - $pPHPExcel = clone $pPHPExcel; - - // Update media links - $sheetCount = $pPHPExcel->getSheetCount(); - for ($i = 0; $i < $sheetCount; ++$i) { - for ($j = 0; $j < $pPHPExcel->getSheet($i)->getDrawingCollection()->count(); ++$j) { - if ($pPHPExcel->getSheet($i)->getDrawingCollection()->offsetGet($j) instanceof PHPExcel_Worksheet_BaseDrawing) { - $imgTemp =& $pPHPExcel->getSheet($i)->getDrawingCollection()->offsetGet($j); - $imgTemp->setPath('zip://' . $pFilename . '#media/' . $imgTemp->getFilename(), false); - } - } - } - - // Create XML writer - $objWriter = new xmlWriter(); - $objWriter->openMemory(); - $objWriter->setIndent(true); - - // XML header - $objWriter->startDocument('1.0','UTF-8','yes'); - - // PHPExcel - $objWriter->startElement('PHPExcel'); - $objWriter->writeAttribute('version', '1.7.4'); - - // Comment - $objWriter->writeComment('This file has been generated using PHPExcel v1.7.4 (http://www.codeplex.com/PHPExcel). It contains a base64 encoded serialized version of the PHPExcel internal object.'); - - // Data - $objWriter->startElement('data'); - $objWriter->writeCData( base64_encode(serialize($pPHPExcel)) ); - $objWriter->endElement(); - - $objWriter->endElement(); - - // Return - return $objWriter->outputMemory(true); - } -} diff --git a/server_synchronize.php b/server_synchronize.php index b49aa9e4e..2c095de80 100644 --- a/server_synchronize.php +++ b/server_synchronize.php @@ -277,6 +277,7 @@ if ((isset($_REQUEST['submit_connect']))) { */ PMA_syncDisplayHeaderSource($src_db); $odd_row = false; + /** * Display the matching tables' names and difference, first */ @@ -339,8 +340,8 @@ if ((isset($_REQUEST['submit_connect']))) { */ if (($num_alter_cols > 0) || ($num_insert_cols > 0) || ($num_remove_cols > 0) || ($num_add_index > 0) || ($num_remove_index > 0)) { - echo '' . __('Click to select') . ''; @@ -351,8 +352,8 @@ if ((isset($_REQUEST['submit_connect']))) { if (isset($update_array[$i]) || isset($insert_array[$i])) { if (isset($update_array[$i][0][$matching_tables_keys[$i][0]]) || isset($insert_array[$i][0][$matching_tables_keys[$i][0]])) { - echo '' . __('Click to select') . ''; } @@ -367,15 +368,15 @@ if ((isset($_REQUEST['submit_connect']))) { $odd_row = PMA_syncDisplayBeginTableRow($odd_row); echo ' '; - echo '
element because TCPDF // does not recognize e.g.
+ ' . htmlspecialchars($source_tables_uncommon[$j]) . '' . __('Click to select') . '' . __('Click to select') . ''; if ($row_count[$j] > 0) { - echo '' . __('Click to select') . ''; } @@ -733,8 +734,8 @@ if (isset($_REQUEST['Table_ids'])) { } if (($num_alter_cols > 0) || ($num_insert_cols > 0) || ($num_remove_cols > 0) || ($num_add_index > 0) || ($num_remove_index > 0)) { - echo '' . __('Click to select') . ''; } @@ -761,8 +762,8 @@ if (isset($_REQUEST['Table_ids'])) { if ((isset($matching_tables_keys[$i][0]) && isset($update_array[$i][0][$matching_tables_keys[$i][0]])) || (isset($matching_tables_keys[$i][0]) && isset($insert_array[$i][0][$matching_tables_keys[$i][0]]))) { - echo '' . __('Click to select') . ''; } @@ -789,8 +790,8 @@ if (isset($_REQUEST['Table_ids'])) { */ if (!(in_array($j, $uncommon_table_structure_diff))) { if (isset($uncommon_tables[$j])) { - echo '' . __('Click to select') . '' .' '; } } else { @@ -801,8 +802,8 @@ if (isset($_REQUEST['Table_ids'])) { */ if (!(in_array($j, $uncommon_table_data_diff))) { if (isset($row_count[$j]) && ($row_count > 0)) { - echo '' . __('Click to select') . ''; } diff --git a/themes/pmahomme/css/theme_left.css.php b/themes/pmahomme/css/theme_left.css.php index 512516334..757a3db0b 100644 --- a/themes/pmahomme/css/theme_left.css.php +++ b/themes/pmahomme/css/theme_left.css.php @@ -4,7 +4,7 @@ * navigation css file from theme Original * * @package phpMyAdmin-theme - * @subpackage Original + * @subpackage pmahomme */ // unplanned execution path diff --git a/themes/pmahomme/css/theme_print.css.php b/themes/pmahomme/css/theme_print.css.php index 49a0d2363..35f28a497 100644 --- a/themes/pmahomme/css/theme_print.css.php +++ b/themes/pmahomme/css/theme_print.css.php @@ -4,7 +4,7 @@ * print css file from theme Original * * @package phpMyAdmin-theme - * @subpackage Original + * @subpackage pmahomme */ ?> /* For printview */ diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php index 71ebabe07..924a729e1 100644 --- a/themes/pmahomme/css/theme_right.css.php +++ b/themes/pmahomme/css/theme_right.css.php @@ -4,7 +4,7 @@ * main css file from theme Original * * @package phpMyAdmin-theme - * @subpackage Original + * @subpackage pmahomme */ // unplanned execution path @@ -1592,6 +1592,10 @@ code.sql, div.sqlvalidate { width: 98%; } +textarea#partitiondefinition { + height:3em; +} + /* for elements that should be revealed only via js */ .hide { display: none; diff --git a/themes/pmahomme/info.inc.php b/themes/pmahomme/info.inc.php index d9b4e5646..a39a0fb23 100644 --- a/themes/pmahomme/info.inc.php +++ b/themes/pmahomme/info.inc.php @@ -4,7 +4,7 @@ * Theme information * * @package phpMyAdmin-theme - * @subpackage Original + * @subpackage pmahomme */ /** diff --git a/themes/pmahomme/layout.inc.php b/themes/pmahomme/layout.inc.php index 604982aeb..333825648 100644 --- a/themes/pmahomme/layout.inc.php +++ b/themes/pmahomme/layout.inc.php @@ -5,7 +5,7 @@ * for detailed layout configuration please refer to the css files * * @package phpMyAdmin-theme - * @subpackage Original + * @subpackage pmahomme */ /**