Browse Source

first commit

zhuliang 7 years ago
parent
commit
28adbb31bc
100 changed files with 51997 additions and 0 deletions
  1. 236 0
      backend/RTP/Common/EasyFunction.php
  2. 63 0
      backend/RTP/Common/UpdateFunction.php
  3. 150 0
      backend/RTP/Module/AutomaticallyModule.class.php
  4. 304 0
      backend/RTP/Module/DatabaseModule.class.php
  5. 84 0
      backend/RTP/Module/ExceptionModule.class.php
  6. 90 0
      backend/RTP/Module/FileModule.class.php
  7. 119 0
      backend/RTP/Module/OutputStorageModule.class.php
  8. 124 0
      backend/RTP/Module/RegistryModule.class.php
  9. 3 0
      backend/RTP/config/version.php
  10. 395 0
      backend/RTP/db/eolinker_os_mysql.sql
  11. 1153 0
      backend/RTP/extend/excel/PHPExcel.php
  12. 81 0
      backend/RTP/extend/excel/PHPExcel/Autoloader.php
  13. 290 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/APC.php
  14. 368 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/CacheBase.php
  15. 208 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/DiscISAM.php
  16. 103 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/ICache.php
  17. 149 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Igbinary.php
  18. 308 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Memcache.php
  19. 118 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Memory.php
  20. 133 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/MemoryGZip.php
  21. 129 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/MemorySerialized.php
  22. 200 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/PHPTemp.php
  23. 307 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/SQLite.php
  24. 346 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/SQLite3.php
  25. 289 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Wincache.php
  26. 231 0
      backend/RTP/extend/excel/PHPExcel/CachedObjectStorageFactory.php
  27. 94 0
      backend/RTP/extend/excel/PHPExcel/CalcEngine/CyclicReferenceStack.php
  28. 151 0
      backend/RTP/extend/excel/PHPExcel/CalcEngine/Logger.php
  29. 4391 0
      backend/RTP/extend/excel/PHPExcel/Calculation.php
  30. 676 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Database.php
  31. 1553 0
      backend/RTP/extend/excel/PHPExcel/Calculation/DateTime.php
  32. 2650 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Engineering.php
  33. 46 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Exception.php
  34. 45 0
      backend/RTP/extend/excel/PHPExcel/Calculation/ExceptionHandler.php
  35. 2359 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Financial.php
  36. 622 0
      backend/RTP/extend/excel/PHPExcel/Calculation/FormulaParser.php
  37. 176 0
      backend/RTP/extend/excel/PHPExcel/Calculation/FormulaToken.php
  38. 148 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Function.php
  39. 760 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Functions.php
  40. 285 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Logical.php
  41. 879 0
      backend/RTP/extend/excel/PHPExcel/Calculation/LookupRef.php
  42. 1459 0
      backend/RTP/extend/excel/PHPExcel/Calculation/MathTrig.php
  43. 3745 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Statistical.php
  44. 651 0
      backend/RTP/extend/excel/PHPExcel/Calculation/TextData.php
  45. 111 0
      backend/RTP/extend/excel/PHPExcel/Calculation/Token/Stack.php
  46. 351 0
      backend/RTP/extend/excel/PHPExcel/Calculation/functionlist.txt
  47. 1032 0
      backend/RTP/extend/excel/PHPExcel/Cell.php
  48. 187 0
      backend/RTP/extend/excel/PHPExcel/Cell/AdvancedValueBinder.php
  49. 115 0
      backend/RTP/extend/excel/PHPExcel/Cell/DataType.php
  50. 492 0
      backend/RTP/extend/excel/PHPExcel/Cell/DataValidation.php
  51. 102 0
      backend/RTP/extend/excel/PHPExcel/Cell/DefaultValueBinder.php
  52. 124 0
      backend/RTP/extend/excel/PHPExcel/Cell/Hyperlink.php
  53. 47 0
      backend/RTP/extend/excel/PHPExcel/Cell/IValueBinder.php
  54. 680 0
      backend/RTP/extend/excel/PHPExcel/Chart.php
  55. 561 0
      backend/RTP/extend/excel/PHPExcel/Chart/Axis.php
  56. 390 0
      backend/RTP/extend/excel/PHPExcel/Chart/DataSeries.php
  57. 333 0
      backend/RTP/extend/excel/PHPExcel/Chart/DataSeriesValues.php
  58. 46 0
      backend/RTP/extend/excel/PHPExcel/Chart/Exception.php
  59. 472 0
      backend/RTP/extend/excel/PHPExcel/Chart/GridLines.php
  60. 486 0
      backend/RTP/extend/excel/PHPExcel/Chart/Layout.php
  61. 170 0
      backend/RTP/extend/excel/PHPExcel/Chart/Legend.php
  62. 126 0
      backend/RTP/extend/excel/PHPExcel/Chart/PlotArea.php
  63. 363 0
      backend/RTP/extend/excel/PHPExcel/Chart/Properties.php
  64. 20 0
      backend/RTP/extend/excel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt
  65. 883 0
      backend/RTP/extend/excel/PHPExcel/Chart/Renderer/jpgraph.php
  66. 86 0
      backend/RTP/extend/excel/PHPExcel/Chart/Title.php
  67. 338 0
      backend/RTP/extend/excel/PHPExcel/Comment.php
  68. 611 0
      backend/RTP/extend/excel/PHPExcel/DocumentProperties.php
  69. 222 0
      backend/RTP/extend/excel/PHPExcel/DocumentSecurity.php
  70. 54 0
      backend/RTP/extend/excel/PHPExcel/Exception.php
  71. 204 0
      backend/RTP/extend/excel/PHPExcel/HashTable.php
  72. 808 0
      backend/RTP/extend/excel/PHPExcel/Helper/HTML.php
  73. 34 0
      backend/RTP/extend/excel/PHPExcel/IComparable.php
  74. 289 0
      backend/RTP/extend/excel/PHPExcel/IOFactory.php
  75. 249 0
      backend/RTP/extend/excel/PHPExcel/NamedRange.php
  76. 289 0
      backend/RTP/extend/excel/PHPExcel/Reader/Abstract.php
  77. 406 0
      backend/RTP/extend/excel/PHPExcel/Reader/CSV.php
  78. 51 0
      backend/RTP/extend/excel/PHPExcel/Reader/DefaultReadFilter.php
  79. 801 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel2003XML.php
  80. 2051 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel2007.php
  81. 520 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel2007/Chart.php
  82. 127 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel2007/Theme.php
  83. 7594 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5.php
  84. 32 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color.php
  85. 77 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color/BIFF5.php
  86. 77 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color/BIFF8.php
  87. 31 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color/BuiltIn.php
  88. 28 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/ErrorCode.php
  89. 669 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Escher.php
  90. 203 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/MD5.php
  91. 81 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/RC4.php
  92. 36 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Style/Border.php
  93. 41 0
      backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Style/FillPattern.php
  94. 46 0
      backend/RTP/extend/excel/PHPExcel/Reader/Exception.php
  95. 850 0
      backend/RTP/extend/excel/PHPExcel/Reader/Gnumeric.php
  96. 549 0
      backend/RTP/extend/excel/PHPExcel/Reader/HTML.php
  97. 39 0
      backend/RTP/extend/excel/PHPExcel/Reader/IReadFilter.php
  98. 46 0
      backend/RTP/extend/excel/PHPExcel/Reader/IReader.php
  99. 696 0
      backend/RTP/extend/excel/PHPExcel/Reader/OOCalc.php
  100. 0 0
      backend/RTP/extend/excel/PHPExcel/Reader/SYLK.php

+ 236 - 0
backend/RTP/Common/EasyFunction.php

@@ -0,0 +1,236 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+
+use RTP\Module as M;
+
+$filePaths = NULL;
+
+/**
+ * 快捷数据库操作函数
+ */
+function getDatabase($isNewInstance = false)
+{
+    return $isNewInstance ? M\DatabaseModule::getNewInstance() : M\DatabaseModule::getInstance();
+}
+
+/**
+ * 快捷完成请求函数,用于一次性按顺序返回所有信息,无须担心Cookie放置位置。
+ * 注意,需要配合P()函数使用
+ */
+function quickFlush()
+{
+    ob_start();
+    $outputFlush = M\OutputStorageModule::getAll();
+    if (is_null($outputFlush))
+        return;
+    foreach ($outputFlush as $value) {
+        echo $value;
+    }
+    //输出缓冲区并且清除缓冲区内容
+    ob_end_flush();
+    M\OutputStorageModule::clean();
+}
+
+/**
+ * 快捷输入函数
+ */
+function quickInput($paramName, $defaultValue = NULL)
+{
+    switch (strtolower(AT)) {
+        case 'auto' :
+            {
+                if (is_null($_GET[$paramName]) || $_GET[$paramName] == '') {
+                    if (is_null($_POST[$paramName] || $_POST[$paramName] == ''))
+                        return $defaultValue;
+                    else
+                        return $_POST[$paramName];
+                } else
+                    return $_GET[$paramName];
+            }
+        case 'post' :
+            {
+                if (is_null($_POST[$paramName]) || $_POST[$paramName] == '')
+                    return $defaultValue;
+                else
+                    return $_POST[$paramName];
+            }
+        case 'get' :
+            {
+                if (is_null($_GET[$paramName]) || $_GET[$paramName] == '')
+                    return $defaultValue;
+                else
+                    return $_GET[$paramName];
+            }
+        default :
+            return NULL;
+    }
+}
+
+/**
+ * 安全输入函数,获取参数并且对参数进行过滤
+ */
+function securelyInput($paramName, $defaultValue = NULL)
+{
+    switch (strtolower(AT)) {
+        case 'auto' :
+            {
+                if (is_null($_GET[$paramName]) || $_GET[$paramName] == '') {
+                    if (is_null($_POST[$paramName]) || $_POST[$paramName] == '')
+                        return $defaultValue;
+                    else
+                        return cleanFormat($_POST[$paramName]);
+                } else
+                    return cleanFormat($_GET[$paramName]);
+            }
+        case 'post' :
+            {
+                if (is_null($_POST[$paramName]) || $_POST[$paramName] == '')
+                    return $defaultValue;
+                else
+                    return cleanFormat($_POST[$paramName]);
+            }
+        case 'get' :
+            {
+                if (is_null($_GET[$paramName]) || $_GET[$paramName] == '')
+                    return $defaultValue;
+                else
+                    return cleanFormat($_GET[$paramName]);
+            }
+        default :
+            return NULL;
+    }
+}
+
+/**
+ * 快捷输出函数:output,默认数组输出json,字符串直接输出
+ */
+function quickOutput($output)
+{
+    echo is_array($output) ? json_encode($output) : $output;
+}
+
+/**
+ * 结束输出函数:output,默认数组输出json,字符串直接输出,并且输出之后停止程序
+ */
+function exitOutput($output)
+{
+    exit(is_array($output) ? json_encode($output) : $output);
+}
+
+/**
+ * 快捷序列化输出函数,需要配合quickFlush()函数使用
+ */
+function serialPrint($output, $distinct = FALSE)
+{
+    if ($distinct)
+        if (M\OutputStorageModule::isExist($output))
+            return;
+    M\OutputStorageModule::set($output);
+}
+
+/**
+ * 快速引入文件函数
+ */
+function quickRequire($filePath)
+{
+    global $filePaths;
+    if (is_null($filePaths))
+        $filePaths = array();
+
+    if (!isset($filePaths[$filePath])) {
+        if (is_file($filePath)) {
+            //require不使用函数形式是因为参数带括号会降低运行速度
+            require $filePath;
+            $filePaths[$filePath] = TRUE;
+        } else {
+            $filePaths[$filePath] = FALSE;
+        }
+    }
+}
+
+/**
+ * 快捷Session操作函数:session
+ */
+function quickSession(&$key, &$value)
+{
+    if (session_status() == 1)
+        session_start();
+    if (isset($_SESSION[$key])) {
+        if (isset($value))
+            $_SESSION[$key] = $value;
+        return $_SESSION[$key];
+    } else
+        $_SESSION[$key] = $value;
+}
+
+/**
+ * 格式清除函数
+ */
+function cleanFormat(&$value)
+{
+    return htmlspecialchars(stripcslashes(trim($value)));
+}
+
+/**
+ * 换行输出数组信息
+ */
+function printFormatted(array $info)
+{
+    foreach ($info as $key => $value) {
+        echo "$key:$value</br>";
+    };
+}
+
+/**
+ * 判断请求协议是否为https
+ * @return bool
+ */
+function is_https()
+{
+    if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
+        return TRUE;
+    } elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
+        return TRUE;
+    } elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ * 异常处理
+ * @param $error_level
+ * @param $error_str
+ * @throws Exception
+ */
+function err_handler($error_level, $error_str)
+{
+    throw new Exception("[$error_level] $error_str", 100001);
+}
+
+/**
+ * 判断session是否已开启
+ * @return bool
+ */
+function is_session_started()
+{
+    return function_exists('session_status') ? (PHP_SESSION_ACTIVE == session_status()) : (!empty (session_id()));
+}
+
+?>

+ 63 - 0
backend/RTP/Common/UpdateFunction.php

@@ -0,0 +1,63 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+//本文件用于版本更新之后更新相关数据用途
+
+//针对1.4之前的版本,在项目配置文件中增加更多的选项
+$db_url = DB_URL;
+$db_port = DB_PORT;
+$db_user = DB_USER;
+$db_password = DB_PASSWORD;
+$db_name = DB_NAME;
+$websiteName = defined('WEBSITE_NAME') ? WEBSITE_NAME : 'eolinker开源版';
+$prefixion = defined('DB_TABLE_PREFIXION') ? DB_TABLE_PREFIXION : 'eo';
+$language = defined('LANGUAGE') ? LANGUAGE : 'zh-cn';
+
+$config = "<?php
+//主机地址
+defined('DB_URL') or define('DB_URL', '{$db_url}');
+
+//主机端口,默认mysql为3306
+defined('DB_PORT') or define('DB_PORT', '{$db_port}');
+
+//连接数据库的用户名
+defined('DB_USER') or define('DB_USER', '{$db_user}');
+
+//连接数据库的密码,推荐使用随机生成的字符串
+defined('DB_PASSWORD') or define('DB_PASSWORD', '{$db_password}');
+
+//数据库名
+defined('DB_NAME') or define('DB_NAME', '{$db_name}');
+
+//是否允许新用户注册
+defined('ALLOW_REGISTER') or define('ALLOW_REGISTER', TRUE);
+
+//是否允许更新项目,如果设置为FALSE,那么自动更新和手动更新都将失效
+defined('ALLOW_UPDATE') or define('ALLOW_UPDATE', TRUE);
+
+//网站名称
+defined('WEBSITE_NAME') or define('WEBSITE_NAME', '{$websiteName}');
+
+//数据表前缀
+defined('DB_TABLE_PREFIXION') or define('DB_TABLE_PRIFIXION', '{$prefixion}');
+
+//语言
+defined('LANGUAGE') or define('LANGUAGE', '{$language}')
+?>";
+
+$configFile = file_put_contents(PATH_FW . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'eo_config.php', $config);
+?>

+ 150 - 0
backend/RTP/Module/AutomaticallyModule.class.php

@@ -0,0 +1,150 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+
+namespace RTP\Module;
+
+class AutomaticallyModule
+{
+    private static $path;
+    private static $groupName;
+    private static $controllerName;
+    private static $moduleName;
+    private static $operationName;
+    private static $daoName;
+    private static $modelName;
+
+    public static function start()
+    {
+        //注册自动载入方法
+        spl_autoload_register('self::autoloadUserController');
+        spl_autoload_register('self::autoloadUserModule');
+        spl_autoload_register('self::autoloadUserDao');
+        spl_autoload_register('self::autoloadRTPModule');
+
+        /*
+         * 检查项目配置文件是否已经存在,如果存在则该项目可能已经部署完成,否则重新开始配置项目
+         */
+        if (file_exists(PATH_FW . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'eo_config.php')) {
+            quickRequire(PATH_FW . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'eo_config.php');
+        }
+
+        /*
+         * 检查版本配置文件是否存在
+         */
+        if (file_exists(PATH_FW . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'version.php')) {
+            quickRequire(PATH_FW . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'version.php');
+        }
+
+        self::$groupName = cleanFormat($_GET['g']);
+        self::$controllerName = cleanFormat($_GET['c']);
+        self::$moduleName = cleanFormat($_GET['c']);
+        self::$operationName = cleanFormat($_GET['o']);
+
+        //检查pathinfo完整性
+        if (!isset(self::$groupName))
+            throw new ExceptionModule(11002, 'error in lack of groupName');
+        else
+            if (!isset(self::$controllerName))
+                throw new ExceptionModule(11003, 'error in lack of controllerName');
+            else
+                if (!isset(self::$operationName))
+                    throw new ExceptionModule(11004, 'error in lack of operationName');
+        //实例化控制器对象
+        $class = new \ReflectionClass(self::$controllerName . DIR_CONTROLLER);
+
+        //系统魔术方法
+        $php_magic_methods = array(
+            '__construct',
+            '__destruct',
+            '__call',
+            '__callstatic',
+            '__get',
+            '__set',
+            '__isset',
+            '__unset',
+            '__sleep',
+            '__wakeup',
+            '__tostring',
+            '__invoke',
+            '__set_state',
+            '__clone',
+            '__debugInfo'
+        );
+        //如果拥有相应的操作方法,并且这些方法并不是php的魔术方法
+        if (!in_array(strtolower(self::$operationName), $php_magic_methods) && $class->hasMethod(self::$operationName)) {
+            //获取方法
+            $method = $class->getMethod(self::$operationName);
+            //判断是否是公用方法
+            if ($method->isPublic()) {
+                //判断是否是静态方法,静态与非静态的执行操作有所不同
+                if ($method->isStatic()) {
+                    $method->invoke(NULL);
+                } else {
+                    $method->invoke($class->newInstance());
+                }
+            } else {
+                //操作无法访问
+                throw new ExceptionModule(11005, 'operation isn\'t a public function');
+            }
+        } else {
+            //操作无法访问
+            throw new ExceptionModule(11006, 'undefined operation or illegal operation name');
+        }
+    }
+
+    /**
+     * 自动载入用户自定义控制器
+     */
+    public static function autoloadUserController($className)
+    {
+        $path = realpath(PATH_APP . DIRECTORY_SEPARATOR . self::$groupName . DIRECTORY_SEPARATOR . DIR_CONTROLLER . DIRECTORY_SEPARATOR . self::$controllerName . DIR_CONTROLLER . '.class.php');
+        quickRequire($path);
+        //当控制器完成路由之后,取消自动载入控制器的路由,加快模块的加载速度
+        spl_autoload_unregister('self::autoloadUserController');
+    }
+
+    /**
+     * 自动载入用户自定义模块
+     */
+    public static function autoloadUserModule($className)
+    {
+        $path = realpath(PATH_APP . DIRECTORY_SEPARATOR . self::$groupName . DIRECTORY_SEPARATOR . DIR_MODULE . DIRECTORY_SEPARATOR . $className . '.class.php');
+        quickRequire($path);
+    }
+
+    /**
+     * 自动载入用户自定义Dao
+     */
+    public static function autoloadUserDao($className)
+    {
+        $path = realpath(PATH_APP . DIRECTORY_SEPARATOR . self::$groupName . DIRECTORY_SEPARATOR . DIR_DAO . DIRECTORY_SEPARATOR . $className . '.class.php');
+        quickRequire($path);
+    }
+
+    /**
+     * 自动载入框架模块
+     */
+    public static function autoloadRTPModule($className)
+    {
+        $path = realpath(PATH_FW . PATH_MODULE) . DIRECTORY_SEPARATOR . str_replace('RTP\Module\\', '', $className) . '.class.php';
+        quickRequire($path);
+    }
+
+}
+
+?>

+ 304 - 0
backend/RTP/Module/DatabaseModule.class.php

@@ -0,0 +1,304 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+
+namespace RTP\Module;
+
+class DatabaseModule
+{
+	private static $instance;
+	private static $db_con;
+	private $db_history;
+	//上一次操作结果
+	private $last_result;
+	private $last_sql;
+
+	/**
+	 * 获取实例
+	 */
+	public static function getInstance()
+	{
+		//如果已经含有一个实例则直接返回实例
+		if (!is_null(self::$instance))
+		{
+			return self::$instance;
+		}
+		else
+		{
+			//如果没有实例则新建
+			return self::getNewInstance();
+		}
+	}
+
+	/**
+	 * 获取一个新的实例
+	 */
+	public static function getNewInstance()
+	{
+		self::$instance = null;
+		self::$instance = new self;
+		return self::$instance;
+	}
+
+	/**
+	 * 创建对象时自动连接数据库
+	 */
+	protected function __construct()
+	{
+		self::connect();
+	}
+
+	/**
+	 * 销毁对象时自动断开数据库连接
+	 */
+	function __destruct()
+	{
+		self::close();
+	}
+
+	/**
+	 * 连接主机
+	 */
+	private function connect()
+	{
+		$conInfo = DB_TYPE . ':host=' . DB_URL . ';port=' . DB_PORT . ';dbname=' . DB_NAME . ';charset=utf8';
+
+		//是否保持持久化链接
+		if (DB_PERSISTENT_CONNECTION)
+		{
+			$option = array(
+				\PDO::MYSQL_ATTR_INIT_COMMAND => "set names 'utf8'",
+				\PDO::ATTR_PERSISTENT => TRUE,
+				\PDO::ATTR_EMULATE_PREPARES => FALSE,
+                \PDO::ATTR_STRINGIFY_FETCHES => FALSE
+			);
+		}
+		else
+		{
+			$option = array(
+				\PDO::MYSQL_ATTR_INIT_COMMAND => "set names 'utf8'",
+				\PDO::ATTR_EMULATE_PREPARES => FALSE,
+                \PDO::ATTR_STRINGIFY_FETCHES => FALSE
+			);
+		}
+
+		//尝试连接数据库
+		try
+		{
+			self::$db_con = new \PDO($conInfo, DB_USER, DB_PASSWORD, $option);
+
+		}
+		catch(\PDOException $e)
+		{
+			if (DEBUG)
+				print_r($e -> getMessage());
+			exit ;
+		}
+	}
+
+	/**
+	 * 关闭主机连接
+	 */
+	public function close()
+	{
+		self::$db_con = NULL;
+		self::$instance = NULL;
+	}
+
+	/**
+	 * 执行无返回值的数据库操作并且返回受影响的记录条数
+	 */
+	public function execute($sql)
+	{
+		$this -> last_sql = $sql;
+		$result = self::$db_con -> exec($sql);
+		$this -> getError();
+		return $result;
+	}
+
+	/**
+	 * 执行操作并返回一条数据
+	 */
+	public function query($sql)
+	{
+		$this -> last_sql = $sql;
+		$this -> db_history = self::$db_con -> query($sql);
+		$this -> getError();
+		$this -> last_result = $this -> db_history -> fetch(\PDO::FETCH_ASSOC);
+		return $this -> last_result;
+	}
+
+	/**
+	 * 执行操作并返回多条数据(如果可能)
+	 */
+	public function queryAll($sql)
+	{
+		$this -> last_sql = $sql;
+		$this -> db_history = self::$db_con -> query($sql);
+		$this -> getError();
+		$this -> last_result = $this -> db_history -> fetchAll(\PDO::FETCH_ASSOC);
+		return $this -> last_result;
+	}
+
+	/**
+	 * prepare方式执行操作,返回一条数据,防止sql注入
+	 */
+	public function prepareExecute($sql, $params = NULL)
+	{
+		$this -> last_sql = $sql;
+		$this -> db_history = self::$db_con -> prepare($sql);
+		$this -> getError();
+		if (is_null($params))
+		{
+			$this -> db_history -> execute();
+		}
+		else
+		{
+			$this -> db_history -> execute($params);
+		}
+		$this -> getError();
+		$this -> last_result = $this -> db_history -> fetch(\PDO::FETCH_ASSOC);
+
+		return $this -> last_result;
+	}
+
+	/**
+	 * prepare方式执行操作,返回多条数据(如果可能),防止sql注入
+	 */
+	public function prepareExecuteAll($sql, $params = NULL)
+	{
+		$this -> last_sql = $sql;
+		$this -> db_history = self::$db_con -> prepare($sql);
+		$this -> getError();
+		if (is_null($params))
+		{
+			$this -> db_history -> execute();
+		}
+		else
+		{
+			$this -> db_history -> execute($params);
+		}
+		$this -> getError();
+		$this -> last_result = $this -> db_history -> fetchAll(\PDO::FETCH_ASSOC);
+
+		return $this -> last_result;
+	}
+
+	/**
+	 * prepare方式,以新的参数重新执行一次查询,返回一条数据
+	 */
+	public function prepareRexecute($params)
+	{
+		$this -> db_history -> execute($params);
+		$this -> getError();
+		$this -> last_result = $this -> db_history -> fetch(\PDO::FETCH_ASSOC);
+		return $this -> last_result;
+	}
+
+	/**
+	 * prepare方式,以新的参数重新执行一次查询,返回多条数据(如果可能)
+	 */
+	public function prepareRexecuteAll($params)
+	{
+		$this -> db_history -> execute($params);
+		$this -> getError();
+		$this -> last_result = $this -> db_history -> fetchAll(\PDO::FETCH_ASSOC);
+		return $this -> last_result;
+	}
+
+	/**
+	 * 获取上一次操作影响的行数
+	 */
+	public function getAffectRow()
+	{
+		if (is_null($this -> db_history))
+		{
+			return 0;
+		}
+		else
+		{
+			return $this -> db_history -> rowCount();
+		}
+	}
+
+	/**
+	 * 获取最后执行的SQL语句
+	 */
+	public function getLastSQL()
+	{
+		return $this -> last_sql;
+	}
+
+	/**
+	 * 获取最后插入行的ID或序列值
+	 */
+	public function getLastInsertID()
+	{
+		return self::$db_con -> lastInsertId();
+	}
+
+	/**
+	 * 获取错误信息
+	 */
+	public function getError()
+	{
+		$result = self::$db_con -> errorInfo();
+		if (DEBUG)
+		{
+			if ($result[0] != 00000)
+			{
+				$error = json_encode(self::$db_con -> errorInfo());
+				throw new ExceptionModule(12000, "database error in:$error");
+			}
+		}
+		else
+		{
+			if ($result[0] != 00000)
+			{
+				return FALSE;
+			}
+			else
+				return TRUE;
+		}
+	}
+
+	/**
+	 * 开始事务
+	 */
+	public function beginTransaction()
+	{
+		self::$db_con -> beginTransaction();
+	}
+
+	/**
+	 * 回滚事务
+	 */
+	public function rollback()
+	{
+		self::$db_con -> rollback();
+	}
+
+	/**
+	 * 提交事务
+	 */
+	public function commit()
+	{
+		self::$db_con -> commit();
+	}
+
+}
+?>

+ 84 - 0
backend/RTP/Module/ExceptionModule.class.php

@@ -0,0 +1,84 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+namespace RTP\Module;
+class ExceptionModule extends \Exception
+{
+
+	/**
+	 * 构造方法,传递错误信息以及错误码
+	 */
+	public function __construct($code = 10000, $info)
+	{
+		//如果记录文件夹不存在则新建
+		if (!file_exists('./log/'))
+		{
+			//如果新建失败则抛出异常,可能权限不足
+			if (!mkdir('./log/'))
+			{
+				//此处不用ExceptionModule进行异常抛出,因为如果权限不足,此异常会无限抛出进入死循环
+				throw new \Exception("can not create directory,please check you app's root file system authorization", 13001);
+			}
+		}
+		parent::__construct($info, $code);
+	}
+
+	public function printError($isStop = FALSE)
+	{
+		//如果非调试模式,则取消所有的错误输出
+		if (!DEBUG)
+		{
+			$infoJson = array('errorCode' => $this -> getCode());
+
+			//输出json
+			echo json_encode($infoJson);
+
+			$infoJson = array(
+				'datetime' => date('Y/M/d H:i:s', time()),
+				'errorCode' => $this -> getCode(),
+				'info' => $this -> getMessage(),
+				'wrongFile' => $this -> getFile(),
+				'wrongLine' => $this -> getLine()
+			);
+
+			//将错误信息记录到文件
+			$logInfo = "{$infoJson['datetime']}=>[code:{$infoJson['errorCode']};info:{$infoJson['info']};wrongFile:{$infoJson['wrongFile']};wrongLine:{$infoJson['wrongLine']}];\n";
+			file_put_contents('./log/' . date('Y_M_d', time()) . '.txt', $logInfo, FILE_APPEND);
+		}
+		else
+		{
+			$infoJson = array(
+				'datetime' => date('Y/M/d H:i:s', time()),
+				'errorCode' => $this -> getCode(),
+				'info' => $this -> getMessage(),
+				'wrongFile' => $this -> getFile(),
+				'wrongLine' => $this -> getLine()
+			);
+
+			//输出自然语言
+			printFormatted($infoJson);
+
+			$logInfo = "{$infoJson['datetime']}=>[code:{$infoJson['errorCode']};info:{$infoJson['info']};wrongFile:{$infoJson['wrongFile']};wrongLine:{$infoJson['wrongLine']}];\n";
+			file_put_contents('./log/' . date('Y_M_d', time()) . '.txt', $logInfo, FILE_APPEND);
+		}
+
+		if ($isStop)
+			exit ;
+	}
+
+}
+?>

+ 90 - 0
backend/RTP/Module/FileModule.class.php

@@ -0,0 +1,90 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+
+namespace RTP\Module;
+
+class FileModule
+{
+	/**
+	 * 自动在用户目录下面创建空白index.html文件,用于保护文件目录
+	 */
+	public static function createSecurityIndex()
+	{
+		$path = PATH_APP;
+		$dirs = array();
+		$ban_dirs = array(
+			'./',
+			'.',
+			'../',
+			'..'
+		);
+		self::getAllDirs($path, $dirs, $ban_dirs);
+
+		foreach ($dirs as $dir)
+		{
+			if (file_exists($dir . '/index.html') || file_exists($dir . '/index.php'))
+				continue;
+			else
+			{
+				$file = fopen($dir . '/index.html', 'w');
+				fwrite($file, '');
+				fclose($file);
+			}
+		}
+	}
+
+	/**
+	 * 获取路径下的所有目录
+	 * @param String $path 目标路径
+	 * @param array $dirs 用于储存返回路径的数组
+	 * @param array $ban_dirs [可选]需要过滤的目录的相对地址的数组
+	 */
+	public static function getAllDirs($path, array &$dirs, array &$ban_dirs = array())
+	{
+		$paths = scandir($path);
+		foreach ($paths as $nextPath)
+		{
+			if (!in_array($nextPath, $ban_dirs) && is_dir($path . DIRECTORY_SEPARATOR . $nextPath))
+			{
+				$dirs[] = realpath($path . DIRECTORY_SEPARATOR . urlencode($nextPath));
+				self::getAllDirs($path . DIRECTORY_SEPARATOR . $nextPath, $dirs, $ban_dirs);
+			}
+		}
+	}
+
+	/**
+	 * 获取路径下的所有文件
+	 * @param String $path 目标路径
+	 * @param array $dirs 用于储存返回路径的数组
+	 * @param array $ban_dirs [可选]需要过滤的文件名的数组
+	 */
+	public static function getAllFiles($path, &$dirs, &$ban_dirs = array())
+	{
+		$paths = scandir($path);
+		foreach ($paths as $nextPath)
+		{
+			if (!in_array($nextPath, $ban_dirs) && is_file($path . DIRECTORY_SEPARATOR . $nextPath))
+			{
+				$dirs[] = realpath($path . DIRECTORY_SEPARATOR . urlencode($nextPath));
+				self::getAllFiles($path . DIRECTORY_SEPARATOR . $nextPath, $dirs, $ban_dirs);
+			}
+		}
+	}
+
+}
+?>

+ 119 - 0
backend/RTP/Module/OutputStorageModule.class.php

@@ -0,0 +1,119 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+
+namespace RTP\Module;
+
+Class OutputStorageModule
+{
+	/**
+	 * 注册表变量
+	 */
+	private static $registry = NULL;
+	private static $instance;
+
+	/**
+	 * 获取实例
+	 */
+	public static function getInstance()
+	{
+		//如果已经含有一个实例则直接返回实例
+		if (!is_null(self::$instance))
+		{
+			return self::$instance;
+		}
+		else
+		{
+			//如果没有实例则新建
+			return self::getNewInstance();
+		}
+	}
+
+	/**
+	 * 获取一个新的实例
+	 */
+	public static function getNewInstance()
+	{
+		self::$instance = null;
+		self::$instance = new self;
+		return self::$instance;
+	}
+
+	/**
+	 * 构造函数
+	 */
+	protected function __construct()
+	{
+		if (is_null(self::$registry))
+			self::$registry = array();
+	}
+
+	/**
+	 * 获取储存的数据
+	 */
+	public static function get($offset)
+	{
+		if (isset(self::$registry[$offset]))
+			return self::$registry[$offset];
+		return NULL;
+	}
+
+	/**
+	 * 设置缓存数据值
+	 */
+	public static function set($value)
+	{
+		if (is_null(self::$registry))
+			self::$registry = array();
+
+		self::$registry[] = $value;
+	}
+
+	/**
+	 * 获取所有缓存值
+	 */
+	public static function getAll()
+	{
+		return self::$registry;
+	}
+
+	/**
+	 * 检查缓存值是否已经存在
+	 */
+	public static function isExist($value)
+	{
+		if (is_null(self::$registry))
+		{
+			return FALSE;
+		}
+		if (in_array($value, self::$registry))
+		{
+			return TRUE;
+		}
+		return FALSE;
+	}
+
+	/**
+	 * 清除缓存值
+	 */
+	public static function clean()
+	{
+		self::$registry = NULL;
+	}
+
+}
+?>

+ 124 - 0
backend/RTP/Module/RegistryModule.class.php

@@ -0,0 +1,124 @@
+<?php
+/**
+ * @name eolinker ams open source,eolinker开源版本
+ * @link https://www.eolinker.com/
+ * @package eolinker
+ * @author www.eolinker.com 广州银云信息科技有限公司 ©2015-2018
+ * eoLinker是目前全球领先、国内最大的在线API接口管理平台,提供自动生成API文档、API自动化测试、Mock测试、团队协作等功能,旨在解决由于前后端分离导致的开发效率低下问题。
+ * 如在使用的过程中有任何问题,欢迎加入用户讨论群进行反馈,我们将会以最快的速度,最好的服务态度为您解决问题。
+ *
+ * eoLinker AMS开源版的开源协议遵循Apache License 2.0,如需获取最新的eolinker开源版以及相关资讯,请访问:https://www.eolinker.com/#/os/download
+ *
+ * 官方网站:https://www.eolinker.com/
+ * 官方博客以及社区:http://blog.eolinker.com/
+ * 使用教程以及帮助:http://help.eolinker.com/
+ * 商务合作邮箱:market@eolinker.com
+ * 用户讨论QQ群:284421832
+ */
+
+namespace RTP\Module;
+
+Class RegistryModule
+{
+	private static $registry = NULL;
+	private static $instance;
+
+	/**
+	 * 获取实例
+	 */
+	public static function getInstance()
+	{
+		//如果已经含有一个实例则直接返回实例
+		if (!is_null(self::$instance))
+		{
+			return self::$instance;
+		}
+		else
+		{
+			//如果没有实例则新建
+			return self::getNewInstance();
+		}
+	}
+
+	/**
+	 * 获取一个新的实例
+	 */
+	public static function getNewInstance()
+	{
+		self::$instance = null;
+		self::$instance = new self;
+		return self::$instance;
+	}
+
+	protected function __construct()
+	{
+		if (is_null(self::$registry))
+			self::$registry = array();
+	}
+
+	/**
+	 * 获取全局变量
+	 */
+	public static function get($name)
+	{
+		if (isset(self::$registry[$name]))
+			return self::$registry[$name];
+		return NULL;
+	}
+
+	/**
+	 * 设置全局变量
+	 */
+	public static function set($name, $value)
+	{
+		if (is_null(self::$registry))
+			self::$registry = array();
+		self::$registry[$name] = $value;
+	}
+
+	/**
+	 * 删除全局变量
+	 */
+	public static function del($name)
+	{
+		unset(self::$registry[$name]);
+	}
+
+	/**
+	 * 将数组输入全局变量
+	 */
+	public static function setArray($array, $overWrite = FALSE)
+	{
+		while ($kv = each($array))
+		{
+			//如果已经存在重复的键,则覆盖之前的值
+			if ($overWrite && isset(self::$registry[$kv[0]]))
+				self::$registry[$kv[0]] = $kv[1];
+			//否则跳过相同的键
+			else
+			if (isset(self::$registry[$kv[0]]))
+				continue;
+			else
+				self::$registry[$kv[0]] = $kv[1];
+		}
+	}
+
+	/**
+	 * 获取全局变量数组
+	 */
+	public static function getAll()
+	{
+		return self::$registry;
+	}
+
+	/**
+	 * 清除所有全局变量
+	 */
+	public static function clean()
+	{
+		unset(self::$registry);
+		self::$registry = NULL;
+	}
+
+}
+?>

+ 3 - 0
backend/RTP/config/version.php

@@ -0,0 +1,3 @@
+<?php
+defined('OS_VERSION_CODE') or define('OS_VERSION_CODE', '350');
+?>

+ 395 - 0
backend/RTP/db/eolinker_os_mysql.sql

@@ -0,0 +1,395 @@
+DROP TABLE IF EXISTS `eo_api`;
+CREATE TABLE `eo_api` (
+  `apiID` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `apiName` varchar(255) COLLATE utf8_bin NOT NULL,
+  `apiURI` varchar(255) COLLATE utf8_bin NOT NULL,
+  `apiProtocol` tinyint(1) unsigned NOT NULL,
+  `apiFailureMock` text COLLATE utf8_bin,
+  `apiSuccessMock` text COLLATE utf8_bin,
+  `apiRequestType` tinyint(1) unsigned NOT NULL,
+  `apiSuccessMockType` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `apiFailureMockType` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `apiStatus` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `apiUpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `groupID` int(11) unsigned NOT NULL,
+  `projectID` int(11) unsigned NOT NULL,
+  `starred` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `removed` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `removeTime` timestamp NULL DEFAULT NULL,
+  `apiNoteType` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `apiNoteRaw` text COLLATE utf8_bin,
+  `apiNote` text COLLATE utf8_bin,
+  `apiRequestParamType` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  `apiRequestRaw` text COLLATE utf8_bin,
+  `updateUserID` int(11) NOT NULL DEFAULT '0',
+  `mockRule` text COLLATE utf8_bin,
+  `mockResult` text COLLATE utf8_bin,
+  `mockConfig` text COLLATE utf8_bin,
+  `apiSuccessStatusCode` varchar(255) DEFAULT '200',
+  `apiFailureStatusCode` varchar(255) DEFAULT '200',
+  `beforeInject` text NULL,
+  `afterInject` text NULL,
+  PRIMARY KEY (`apiID`,`groupID`,`apiURI`),
+  KEY `groupID` (`groupID`),
+  KEY `apiID` (`apiID`),
+  KEY `projectID` (`projectID`)
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+DROP TABLE IF EXISTS `eo_api_cache`;
+CREATE TABLE `eo_api_cache` (
+  `cacheID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `projectID` int(10) unsigned NOT NULL,
+  `groupID` int(10) unsigned NOT NULL,
+  `apiID` int(10) unsigned NOT NULL,
+  `apiJson` longtext NOT NULL,
+  `starred` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  `updateUserID` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`cacheID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_env`;
+CREATE TABLE `eo_api_env` (
+  `envID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `envName` varchar(255) NOT NULL,
+  `projectID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`envID`,`projectID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_env_front_uri`;
+CREATE TABLE `eo_api_env_front_uri` (
+  `envID` int(10) unsigned NOT NULL,
+  `uri` varchar(255) NOT NULL,
+  `uriID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `applyProtocol` varchar(4) NOT NULL DEFAULT '-1',
+  PRIMARY KEY (`uriID`,`envID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_env_header`;
+CREATE TABLE `eo_api_env_header` (
+  `headerID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `envID` int(11) NOT NULL,
+  `applyProtocol` varchar(255) DEFAULT NULL,
+  `headerName` varchar(255) NOT NULL,
+  `headerValue` text NOT NULL,
+  PRIMARY KEY (`headerID`,`envID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_env_param`;
+CREATE TABLE `eo_api_env_param` (
+  `paramID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `envID` int(10) unsigned NOT NULL,
+  `paramKey` varchar(255) NOT NULL,
+  `paramValue` text NOT NULL,
+  PRIMARY KEY (`paramID`,`envID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_env_param_additional`;
+CREATE TABLE `eo_api_env_param_additional` (
+  `paramID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `envID` int(10) unsigned NOT NULL,
+  `paramKey` varchar(255) NOT NULL,
+  `paramValue` text NOT NULL,
+  PRIMARY KEY (`paramID`,`envID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_group`;
+CREATE TABLE `eo_api_group` (
+  `groupID` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `groupName` varchar(30) COLLATE utf8_bin NOT NULL,
+  `projectID` int(11) unsigned NOT NULL,
+  `parentGroupID` int(10) unsigned NOT NULL DEFAULT '0',
+  `isChild` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  PRIMARY KEY (`groupID`,`projectID`),
+  KEY `groupID` (`groupID`),
+  KEY `projectID` (`projectID`)
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+DROP TABLE IF EXISTS `eo_api_group_order`;
+CREATE TABLE `eo_api_group_order` (
+  `orderID` int(11) NOT NULL AUTO_INCREMENT,
+  `projectID` int(11) NOT NULL,
+  `orderList` text,
+  PRIMARY KEY (`orderID`,`projectID`),
+  UNIQUE KEY `projectID` (`projectID`) USING BTREE
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_header`;
+CREATE TABLE `eo_api_header` (
+  `headerID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `headerName` varchar(255) NOT NULL,
+  `headerValue` text NOT NULL,
+  `apiID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`headerID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_request_param`;
+CREATE TABLE `eo_api_request_param` (
+  `paramID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `paramName` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `paramKey` varchar(255) COLLATE utf8_bin NOT NULL,
+  `paramValue` text COLLATE utf8_bin NOT NULL,
+  `paramType` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  `paramLimit` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `apiID` int(10) unsigned NOT NULL,
+  `paramNotNull` tinyint(1) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`paramID`),
+  KEY `apiID` (`apiID`)
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+DROP TABLE IF EXISTS `eo_api_request_value`;
+CREATE TABLE `eo_api_request_value` (
+  `valueID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `value` text DEFAULT NULL,
+  `valueDescription` varchar(255) DEFAULT NULL,
+  `paramID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`valueID`),
+  KEY `paramID` (`paramID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_result_param`;
+CREATE TABLE `eo_api_result_param` (
+  `paramID` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `paramName` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `paramKey` varchar(255) COLLATE utf8_bin NOT NULL,
+  `apiID` int(11) unsigned NOT NULL,
+  `paramNotNull` tinyint(1) unsigned NOT NULL,
+  PRIMARY KEY (`paramID`),
+  KEY `apiID` (`apiID`)
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+DROP TABLE IF EXISTS `eo_api_result_value`;
+CREATE TABLE `eo_api_result_value` (
+  `valueID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `value` text COLLATE utf8_bin NOT NULL,
+  `valueDescription` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  `paramID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`valueID`),
+  KEY `resultParamID` (`paramID`)
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+DROP TABLE IF EXISTS `eo_api_status_code_group_order`;
+CREATE TABLE `eo_api_status_code_group_order` (
+  `orderID` int(11) NOT NULL AUTO_INCREMENT,
+  `projectID` int(11) NOT NULL,
+  `orderList` text NOT NULL,
+  PRIMARY KEY (`orderID`,`projectID`),
+  UNIQUE KEY `projectID` (`projectID`) USING BTREE
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_test_history`;
+CREATE TABLE `eo_api_test_history` (
+  `testID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `apiID` int(10) unsigned NOT NULL,
+  `requestInfo` longtext,
+  `resultInfo` longtext,
+  `testTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `projectID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`testID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_conn_database`;
+CREATE TABLE `eo_conn_database` (
+  `connID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `dbID` int(10) unsigned NOT NULL,
+  `userID` int(10) unsigned NOT NULL,
+  `userType` tinyint(1) NOT NULL DEFAULT '0',
+  `inviteUserID` int(10) DEFAULT NULL,
+  `partnerNickName` varchar(255) DEFAULT NULL,
+  PRIMARY KEY (`connID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_conn_project`;
+CREATE TABLE `eo_conn_project` (
+  `connID` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `projectID` int(11) unsigned NOT NULL,
+  `userID` int(11) unsigned NOT NULL,
+  `userType` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `inviteUserID` int(11) DEFAULT NULL,
+  `partnerNickName` varchar(255) COLLATE utf8_bin DEFAULT NULL,
+  PRIMARY KEY (`connID`,`projectID`,`userID`),
+  KEY `projectID` (`projectID`),
+  KEY `eo_conn_ibfk_2` (`userID`)
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+DROP TABLE IF EXISTS `eo_database`;
+CREATE TABLE `eo_database` (
+  `dbID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `dbName` varchar(255) NOT NULL,
+  `dbVersion` float unsigned NOT NULL,
+  `dbUpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`dbID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_database_table`;
+CREATE TABLE `eo_database_table` (
+  `dbID` int(10) unsigned NOT NULL,
+  `tableID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `tableName` varchar(255) NOT NULL,
+  `tableDescription` varchar(255) DEFAULT NULL,
+  PRIMARY KEY (`tableID`,`dbID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_database_table_field`;
+CREATE TABLE `eo_database_table_field` (
+  `fieldID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `fieldName` varchar(255) NOT NULL,
+  `fieldType` varchar(10) NOT NULL,
+  `fieldLength` varchar(10) NOT NULL,
+  `isNotNull` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `isPrimaryKey` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `fieldDescription` varchar(255) DEFAULT NULL,
+  `tableID` int(10) unsigned NOT NULL,
+  `defaultValue` varchar(255) DEFAULT NULL,
+  PRIMARY KEY (`fieldID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_message`;
+CREATE TABLE `eo_message` (
+  `msgID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `toUserID` int(10) unsigned NOT NULL,
+  `fromUserID` int(10) unsigned NOT NULL,
+  `msgSendTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `msgType` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `summary` varchar(255) DEFAULT NULL,
+  `msg` text NOT NULL,
+  `isRead` tinyint(1) unsigned NOT NULL DEFAULT '0',
+  `otherMsg` text,
+  PRIMARY KEY (`msgID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project`;
+CREATE TABLE `eo_project` (
+  `projectID` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `projectType` tinyint(1) unsigned NOT NULL,
+  `projectName` varchar(255) COLLATE utf8_bin NOT NULL,
+  `projectUpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `projectVersion` varchar(6) COLLATE utf8_bin NOT NULL DEFAULT '1.0',
+  PRIMARY KEY (`projectID`)
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+DROP TABLE IF EXISTS `eo_project_invite`;
+CREATE TABLE `eo_project_invite` (
+  `projectID` int(11) unsigned NOT NULL,
+  `inviteCode` varchar(6) NOT NULL,
+  `updateTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  PRIMARY KEY (`projectID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_environment`;
+CREATE TABLE `eo_project_environment` (
+  `envID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `envName` varchar(255) NOT NULL,
+  `envURI` varchar(255) NOT NULL,
+  `projectID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`envID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_status_code`;
+CREATE TABLE `eo_project_status_code` (
+  `codeID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `code` varchar(255) NOT NULL,
+  `codeDescription` varchar(255) NOT NULL,
+  `groupID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`codeID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_status_code_group`;
+CREATE TABLE `eo_project_status_code_group` (
+  `groupID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `projectID` int(10) unsigned NOT NULL,
+  `groupName` varchar(255) NOT NULL,
+  `parentGroupID` int(10) unsigned NOT NULL DEFAULT '0',
+  `isChild` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  PRIMARY KEY (`groupID`,`projectID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_user`;
+CREATE TABLE `eo_user` (
+  `userID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `userName` varchar(60) NOT NULL,
+  `userPassword` varchar(60) NOT NULL,
+  `userNickName` varchar(16) NOT NULL DEFAULT '',
+  PRIMARY KEY (`userID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_log_project_operation`;
+CREATE TABLE `eo_log_project_operation` (
+  `opID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `opType` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  `opUserID` int(10) unsigned NOT NULL,
+  `opDesc` text NOT NULL,
+  `opTime` datetime NOT NULL,
+  `opProjectID` int(10) unsigned NOT NULL,
+  `opTarget` tinyint(3) unsigned NOT NULL,
+  `opTargetID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`opID`,`opTargetID`,`opProjectID`,`opUserID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_api_history`;
+CREATE TABLE `eo_api_history` (
+  `historyID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `projectID` int(10) unsigned NOT NULL,
+  `groupID` int(10) unsigned NOT NULL,
+  `apiID` int(10) unsigned NOT NULL,
+  `historyJson` longtext NOT NULL,
+  `updateDesc` varchar(255) NOT NULL,
+  `updateUserID` int(10) unsigned NOT NULL,
+  `updateTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `isNow` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  PRIMARY KEY (`historyID`,`apiID`,`updateTime`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_document_group_order`;
+CREATE TABLE `eo_project_document_group_order` (
+  `orderID` int(11) NOT NULL AUTO_INCREMENT,
+  `projectID` int(11) NOT NULL,
+  `orderList` text NOT NULL,
+  PRIMARY KEY (`orderID`,`projectID`),
+  UNIQUE KEY `projectID` (`projectID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_document_group`;
+CREATE TABLE `eo_project_document_group` (
+  `groupID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `projectID` int(10) unsigned NOT NULL,
+  `groupName` varchar(255) NOT NULL,
+  `parentGroupID` int(10) unsigned NOT NULL DEFAULT '0',
+  `isChild` tinyint(3) unsigned NOT NULL DEFAULT '0',
+  PRIMARY KEY (`groupID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_document`;
+CREATE TABLE `eo_project_document` (
+  `documentID` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `groupID` int(10) unsigned NOT NULL,
+  `projectID` int(10) unsigned NOT NULL,
+  `contentType` tinyint(3) unsigned NOT NULL,
+  `contentRaw` longtext,
+  `content` longtext,
+  `title` varchar(255) NOT NULL,
+  `updateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `userID` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`documentID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_test_case_group`;
+CREATE TABLE `eo_project_test_case_group` (
+  `groupID` int(11) NOT NULL AUTO_INCREMENT COMMENT '分组ID',
+  `groupName` varchar(100) NOT NULL COMMENT '组名',
+  `projectID` int(11) NOT NULL COMMENT '项目ID',
+  `parentGroupID` int(11) NOT NULL DEFAULT '0' COMMENT '父分组',
+  `isChild` tinyint(3) NOT NULL DEFAULT '0' COMMENT '是否子分组',
+  PRIMARY KEY (`groupID`,`projectID`,`parentGroupID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_test_case_group_order`;
+CREATE TABLE `eo_project_test_case_group_order` (
+  `orderID` int(11) NOT NULL AUTO_INCREMENT,
+  `projectID` int(11) NOT NULL,
+  `orderList` text NOT NULL,
+  PRIMARY KEY (`orderID`,`projectID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_test_case_history`;
+CREATE TABLE `eo_project_test_case_history` (
+  `testID` int(11) NOT NULL AUTO_INCREMENT COMMENT '测试ID',
+  `caseID` int(11) NOT NULL COMMENT '用例ID',
+  `result` text COMMENT '测试结果',
+  `testTime` datetime DEFAULT NULL COMMENT '测试时间',
+  `status` tinyint(4) DEFAULT NULL COMMENT '0表示失败,1表示通过',
+  PRIMARY KEY (`testID`,`caseID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_test_case_single`;
+CREATE TABLE `eo_project_test_case_single` (
+  `connID` int(11) NOT NULL AUTO_INCREMENT COMMENT '关联ID',
+  `caseID` int(11) NOT NULL COMMENT '用例ID',
+  `caseData` text COMMENT '内容',
+  `caseCode` text COMMENT '用例代码',
+  `statusCode` varchar(20) DEFAULT NULL,
+  `matchType` tinyint(4) DEFAULT NULL,
+  `matchRule` text,
+  `apiName` varchar(255) NOT NULL COMMENT '接口名称',
+  `apiURI` varchar(255) NOT NULL COMMENT '接口路径',
+  `apiRequestType` tinyint(4) DEFAULT '0' COMMENT '请求参数类型',
+  `orderNumber` int(11),
+  PRIMARY KEY (`connID`,`caseID`)
+) DEFAULT CHARSET=utf8;
+DROP TABLE IF EXISTS `eo_project_test_case`;
+CREATE TABLE `eo_project_test_case` (
+  `caseID` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
+  `projectID` int(11) NOT NULL COMMENT '项目ID',
+  `userID` int(11) NOT NULL COMMENT '用户ID',
+  `caseName` varchar(255) NOT NULL COMMENT '用例名称',
+  `caseDesc` varchar(255) DEFAULT NULL COMMENT '用例描述',
+  `createTime` datetime NOT NULL COMMENT '创建时间',
+  `updateTime` datetime NOT NULL COMMENT '更新时间',
+  `groupID` int(11) NOT NULL COMMENT '分组ID',
+  `caseType` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0表示简单,1表示高级',
+  `caseCode` longtext,
+  PRIMARY KEY (`caseID`,`projectID`,`userID`)
+) DEFAULT CHARSET=utf8;

File diff suppressed because it is too large
+ 1153 - 0
backend/RTP/extend/excel/PHPExcel.php


+ 81 - 0
backend/RTP/extend/excel/PHPExcel/Autoloader.php

@@ -0,0 +1,81 @@
+<?php
+
+PHPExcel_Autoloader::register();
+//    As we always try to run the autoloader before anything else, we can use it to do a few
+//        simple checks and initialisations
+//PHPExcel_Shared_ZipStreamWrapper::register();
+// check mbstring.func_overload
+if (ini_get('mbstring.func_overload') & 2) {
+    throw new PHPExcel_Exception('Multibyte function overloading in PHP must be disabled for string functions (2).');
+}
+PHPExcel_Shared_String::buildCharacterSets();
+
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Autoloader
+{
+    /**
+     * Register the Autoloader with SPL
+     *
+     */
+    public static function register()
+    {
+        if (function_exists('__autoload')) {
+            // Register any existing autoloader function with SPL, so we don't get any clashes
+            spl_autoload_register('__autoload');
+        }
+        // Register ourselves with SPL
+        if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+            return spl_autoload_register(array('PHPExcel_Autoloader', 'load'), true, true);
+        } else {
+            return spl_autoload_register(array('PHPExcel_Autoloader', 'load'));
+        }
+    }
+
+    /**
+     * Autoload a class identified by name
+     *
+     * @param    string    $pClassName        Name of the object to load
+     */
+    public static function load($pClassName)
+    {
+        if ((class_exists($pClassName, false)) || (strpos($pClassName, 'PHPExcel') !== 0)) {
+            // Either already loaded, or not a PHPExcel class request
+            return false;
+        }
+
+        $pClassFilePath = PHPEXCEL_ROOT .
+            str_replace('_', DIRECTORY_SEPARATOR, $pClassName) .
+            '.php';
+
+        if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
+            // Can't load
+            return false;
+        }
+
+        require($pClassFilePath);
+    }
+}

+ 290 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/APC.php

@@ -0,0 +1,290 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_APC
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_APC extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Prefix used to uniquely identify cache data for this worksheet
+     *
+     * @access    private
+     * @var string
+     */
+    private $cachePrefix = null;
+
+    /**
+     * Cache timeout
+     *
+     * @access    private
+     * @var integer
+     */
+    private $cacheTime = 600;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @access  private
+     * @return  void
+     * @throws  PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            if (!apc_store(
+                $this->cachePrefix . $this->currentObjectID . '.cache',
+                serialize($this->currentObject),
+                $this->cacheTime
+            )) {
+                $this->__destruct();
+                throw new PHPExcel_Exception('Failed to store cell ' . $this->currentObjectID . ' in APC');
+            }
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @access  public
+     * @param   string         $pCoord  Coordinate address of the cell to update
+     * @param   PHPExcel_Cell  $cell    Cell to update
+     * @return  PHPExcel_Cell
+     * @throws  PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+        $this->cellCache[$pCoord] = true;
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+    /**
+     * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+     *
+     * @access  public
+     * @param   string  $pCoord  Coordinate address of the cell to check
+     * @throws  PHPExcel_Exception
+     * @return  boolean
+     */
+    public function isDataSet($pCoord)
+    {
+        //    Check if the requested entry is the current object, or exists in the cache
+        if (parent::isDataSet($pCoord)) {
+            if ($this->currentObjectID == $pCoord) {
+                return true;
+            }
+            //    Check if the requested entry still exists in apc
+            $success = apc_fetch($this->cachePrefix.$pCoord.'.cache');
+            if ($success === false) {
+                //    Entry no longer exists in APC, so clear it from the cache array
+                parent::deleteCacheData($pCoord);
+                throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache');
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @access  public
+     * @param   string         $pCoord  Coordinate of the cell
+     * @throws  PHPExcel_Exception
+     * @return  PHPExcel_Cell  Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        if (parent::isDataSet($pCoord)) {
+            $obj = apc_fetch($this->cachePrefix . $pCoord . '.cache');
+            if ($obj === false) {
+                //    Entry no longer exists in APC, so clear it from the cache array
+                parent::deleteCacheData($pCoord);
+                throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache');
+            }
+        } else {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = unserialize($obj);
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @access  public
+     * @param   string  $pCoord  Coordinate address of the cell to delete
+     * @throws  PHPExcel_Exception
+     */
+    public function deleteCacheData($pCoord)
+    {
+        //    Delete the entry from APC
+        apc_delete($this->cachePrefix.$pCoord.'.cache');
+
+        //    Delete the entry from our cell address array
+        parent::deleteCacheData($pCoord);
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @access  public
+     * @param   PHPExcel_Worksheet  $parent  The new worksheet
+     * @throws  PHPExcel_Exception
+     * @return  void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        parent::copyCellCollection($parent);
+        //    Get a new id for the new file name
+        $baseUnique = $this->getUniqueID();
+        $newCachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+        $cacheList = $this->getCellList();
+        foreach ($cacheList as $cellID) {
+            if ($cellID != $this->currentObjectID) {
+                $obj = apc_fetch($this->cachePrefix . $cellID . '.cache');
+                if ($obj === false) {
+                    //    Entry no longer exists in APC, so clear it from the cache array
+                    parent::deleteCacheData($cellID);
+                    throw new PHPExcel_Exception('Cell entry ' . $cellID . ' no longer exists in APC');
+                }
+                if (!apc_store($newCachePrefix . $cellID . '.cache', $obj, $this->cacheTime)) {
+                    $this->__destruct();
+                    throw new PHPExcel_Exception('Failed to store cell ' . $cellID . ' in APC');
+                }
+            }
+        }
+        $this->cachePrefix = $newCachePrefix;
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return  void
+     */
+    public function unsetWorksheetCells()
+    {
+        if ($this->currentObject !== null) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+
+        //    Flush the APC cache
+        $this->__destruct();
+
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+    }
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param  PHPExcel_Worksheet  $parent     The worksheet for this cell collection
+     * @param  array of mixed      $arguments  Additional initialisation arguments
+     */
+    public function __construct(PHPExcel_Worksheet $parent, $arguments)
+    {
+        $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
+
+        if ($this->cachePrefix === null) {
+            $baseUnique = $this->getUniqueID();
+            $this->cachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+            $this->cacheTime = $cacheTime;
+
+            parent::__construct($parent);
+        }
+    }
+
+    /**
+     * Destroy this cell collection
+     */
+    public function __destruct()
+    {
+        $cacheList = $this->getCellList();
+        foreach ($cacheList as $cellID) {
+            apc_delete($this->cachePrefix . $cellID . '.cache');
+        }
+    }
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return  boolean
+     */
+    public static function cacheMethodIsAvailable()
+    {
+        if (!function_exists('apc_store')) {
+            return false;
+        }
+        if (apc_sma_info() === false) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 368 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/CacheBase.php

@@ -0,0 +1,368 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_CacheBase
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+abstract class PHPExcel_CachedObjectStorage_CacheBase
+{
+    /**
+     * Parent worksheet
+     *
+     * @var PHPExcel_Worksheet
+     */
+    protected $parent;
+
+    /**
+     * The currently active Cell
+     *
+     * @var PHPExcel_Cell
+     */
+    protected $currentObject = null;
+
+    /**
+     * Coordinate address of the currently active Cell
+     *
+     * @var string
+     */
+    protected $currentObjectID = null;
+
+    /**
+     * Flag indicating whether the currently active Cell requires saving
+     *
+     * @var boolean
+     */
+    protected $currentCellIsDirty = true;
+
+    /**
+     * An array of cells or cell pointers for the worksheet cells held in this cache,
+     *        and indexed by their coordinate address within the worksheet
+     *
+     * @var array of mixed
+     */
+    protected $cellCache = array();
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The worksheet for this cell collection
+     */
+    public function __construct(PHPExcel_Worksheet $parent)
+    {
+        //    Set our parent worksheet.
+        //    This is maintained within the cache controller to facilitate re-attaching it to PHPExcel_Cell objects when
+        //        they are woken from a serialized state
+        $this->parent = $parent;
+    }
+
+    /**
+     * Return the parent worksheet for this cell collection
+     *
+     * @return    PHPExcel_Worksheet
+     */
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    /**
+     * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+     *
+     * @param    string        $pCoord        Coordinate address of the cell to check
+     * @return    boolean
+     */
+    public function isDataSet($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return true;
+        }
+        //    Check if the requested entry exists in the cache
+        return isset($this->cellCache[$pCoord]);
+    }
+
+    /**
+     * Move a cell object from one address to another
+     *
+     * @param    string        $fromAddress    Current address of the cell to move
+     * @param    string        $toAddress        Destination address of the cell to move
+     * @return    boolean
+     */
+    public function moveCell($fromAddress, $toAddress)
+    {
+        if ($fromAddress === $this->currentObjectID) {
+            $this->currentObjectID = $toAddress;
+        }
+        $this->currentCellIsDirty = true;
+        if (isset($this->cellCache[$fromAddress])) {
+            $this->cellCache[$toAddress] = &$this->cellCache[$fromAddress];
+            unset($this->cellCache[$fromAddress]);
+        }
+
+        return true;
+    }
+
+    /**
+     * Add or Update a cell in cache
+     *
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function updateCacheData(PHPExcel_Cell $cell)
+    {
+        return $this->addCacheData($cell->getCoordinate(), $cell);
+    }
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to delete
+     * @throws    PHPExcel_Exception
+     */
+    public function deleteCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID && !is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObjectID = $this->currentObject = null;
+        }
+
+        if (is_object($this->cellCache[$pCoord])) {
+            $this->cellCache[$pCoord]->detach();
+            unset($this->cellCache[$pCoord]);
+        }
+        $this->currentCellIsDirty = false;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return    string[]
+     */
+    public function getCellList()
+    {
+        return array_keys($this->cellCache);
+    }
+
+    /**
+     * Sort the list of all cell addresses currently held in cache by row and column
+     *
+     * @return    string[]
+     */
+    public function getSortedCellList()
+    {
+        $sortKeys = array();
+        foreach ($this->getCellList() as $coord) {
+            sscanf($coord, '%[A-Z]%d', $column, $row);
+            $sortKeys[sprintf('%09d%3s', $row, $column)] = $coord;
+        }
+        ksort($sortKeys);
+
+        return array_values($sortKeys);
+    }
+
+    /**
+     * Get highest worksheet column and highest row that have cell records
+     *
+     * @return array Highest column name and highest row number
+     */
+    public function getHighestRowAndColumn()
+    {
+        // Lookup highest column and highest row
+        $col = array('A' => '1A');
+        $row = array(1);
+        foreach ($this->getCellList() as $coord) {
+            sscanf($coord, '%[A-Z]%d', $c, $r);
+            $row[$r] = $r;
+            $col[$c] = strlen($c).$c;
+        }
+        if (!empty($row)) {
+            // Determine highest column and row
+            $highestRow = max($row);
+            $highestColumn = substr(max($col), 1);
+        }
+
+        return array(
+            'row'    => $highestRow,
+            'column' => $highestColumn
+        );
+    }
+
+    /**
+     * Return the cell address of the currently active cell object
+     *
+     * @return    string
+     */
+    public function getCurrentAddress()
+    {
+        return $this->currentObjectID;
+    }
+
+    /**
+     * Return the column address of the currently active cell object
+     *
+     * @return    string
+     */
+    public function getCurrentColumn()
+    {
+        sscanf($this->currentObjectID, '%[A-Z]%d', $column, $row);
+        return $column;
+    }
+
+    /**
+     * Return the row address of the currently active cell object
+     *
+     * @return    integer
+     */
+    public function getCurrentRow()
+    {
+        sscanf($this->currentObjectID, '%[A-Z]%d', $column, $row);
+        return (integer) $row;
+    }
+
+    /**
+     * Get highest worksheet column
+     *
+     * @param   string     $row        Return the highest column for the specified row,
+     *                                     or the highest column of any row if no row number is passed
+     * @return  string     Highest column name
+     */
+    public function getHighestColumn($row = null)
+    {
+        if ($row == null) {
+            $colRow = $this->getHighestRowAndColumn();
+            return $colRow['column'];
+        }
+
+        $columnList = array(1);
+        foreach ($this->getCellList() as $coord) {
+            sscanf($coord, '%[A-Z]%d', $c, $r);
+            if ($r != $row) {
+                continue;
+            }
+            $columnList[] = PHPExcel_Cell::columnIndexFromString($c);
+        }
+        return PHPExcel_Cell::stringFromColumnIndex(max($columnList) - 1);
+    }
+
+    /**
+     * Get highest worksheet row
+     *
+     * @param   string     $column     Return the highest row for the specified column,
+     *                                     or the highest row of any column if no column letter is passed
+     * @return  int        Highest row number
+     */
+    public function getHighestRow($column = null)
+    {
+        if ($column == null) {
+            $colRow = $this->getHighestRowAndColumn();
+            return $colRow['row'];
+        }
+
+        $rowList = array(0);
+        foreach ($this->getCellList() as $coord) {
+            sscanf($coord, '%[A-Z]%d', $c, $r);
+            if ($c != $column) {
+                continue;
+            }
+            $rowList[] = $r;
+        }
+
+        return max($rowList);
+    }
+
+    /**
+     * Generate a unique ID for cache referencing
+     *
+     * @return string Unique Reference
+     */
+    protected function getUniqueID()
+    {
+        if (function_exists('posix_getpid')) {
+            $baseUnique = posix_getpid();
+        } else {
+            $baseUnique = mt_rand();
+        }
+        return uniqid($baseUnique, true);
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     * @return    void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        $this->currentCellIsDirty;
+        $this->storeData();
+
+        $this->parent = $parent;
+        if (($this->currentObject !== null) && (is_object($this->currentObject))) {
+            $this->currentObject->attach($this);
+        }
+    }    //    function copyCellCollection()
+
+    /**
+     * Remove a row, deleting all cells in that row
+     *
+     * @param string    $row    Row number to remove
+     * @return void
+     */
+    public function removeRow($row)
+    {
+        foreach ($this->getCellList() as $coord) {
+            sscanf($coord, '%[A-Z]%d', $c, $r);
+            if ($r == $row) {
+                $this->deleteCacheData($coord);
+            }
+        }
+    }
+
+    /**
+     * Remove a column, deleting all cells in that column
+     *
+     * @param string    $column    Column ID to remove
+     * @return void
+     */
+    public function removeColumn($column)
+    {
+        foreach ($this->getCellList() as $coord) {
+            sscanf($coord, '%[A-Z]%d', $c, $r);
+            if ($c == $column) {
+                $this->deleteCacheData($coord);
+            }
+        }
+    }
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return    boolean
+     */
+    public static function cacheMethodIsAvailable()
+    {
+        return true;
+    }
+}

+ 208 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/DiscISAM.php

@@ -0,0 +1,208 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_DiscISAM
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Name of the file for this cache
+     *
+     * @var string
+     */
+    private $fileName = null;
+
+    /**
+     * File handle for this cache file
+     *
+     * @var resource
+     */
+    private $fileHandle = null;
+
+    /**
+     * Directory/Folder where the cache file is located
+     *
+     * @var string
+     */
+    private $cacheDirectory = null;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            fseek($this->fileHandle, 0, SEEK_END);
+
+            $this->cellCache[$this->currentObjectID] = array(
+                'ptr' => ftell($this->fileHandle),
+                'sz'  => fwrite($this->fileHandle, serialize($this->currentObject))
+            );
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        if (!isset($this->cellCache[$pCoord])) {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        fseek($this->fileHandle, $this->cellCache[$pCoord]['ptr']);
+        $this->currentObject = unserialize(fread($this->fileHandle, $this->cellCache[$pCoord]['sz']));
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        parent::copyCellCollection($parent);
+        //    Get a new id for the new file name
+        $baseUnique = $this->getUniqueID();
+        $newFileName = $this->cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
+        //    Copy the existing cell cache file
+        copy($this->fileName, $newFileName);
+        $this->fileName = $newFileName;
+        //    Open the copied cell cache file
+        $this->fileHandle = fopen($this->fileName, 'a+');
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+
+        //    Close down the temporary cache file
+        $this->__destruct();
+    }
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The worksheet for this cell collection
+     * @param    array of mixed        $arguments    Additional initialisation arguments
+     */
+    public function __construct(PHPExcel_Worksheet $parent, $arguments)
+    {
+        $this->cacheDirectory    = ((isset($arguments['dir'])) && ($arguments['dir'] !== null))
+                                    ? $arguments['dir']
+                                    : PHPExcel_Shared_File::sys_get_temp_dir();
+
+        parent::__construct($parent);
+        if (is_null($this->fileHandle)) {
+            $baseUnique = $this->getUniqueID();
+            $this->fileName = $this->cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
+            $this->fileHandle = fopen($this->fileName, 'a+');
+        }
+    }
+
+    /**
+     * Destroy this cell collection
+     */
+    public function __destruct()
+    {
+        if (!is_null($this->fileHandle)) {
+            fclose($this->fileHandle);
+            unlink($this->fileName);
+        }
+        $this->fileHandle = null;
+    }
+}

+ 103 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/ICache.php

@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_ICache
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+interface PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell);
+
+    /**
+     * Add or Update a cell in cache
+     *
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function updateCacheData(PHPExcel_Cell $cell);
+
+    /**
+     * Fetch a cell from cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to retrieve
+     * @return PHPExcel_Cell     Cell that was found, or null if not found
+     * @throws    PHPExcel_Exception
+     */
+    public function getCacheData($pCoord);
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to delete
+     * @throws    PHPExcel_Exception
+     */
+    public function deleteCacheData($pCoord);
+
+    /**
+     * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+     *
+     * @param    string        $pCoord        Coordinate address of the cell to check
+     * @return    boolean
+     */
+    public function isDataSet($pCoord);
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return    string[]
+     */
+    public function getCellList();
+
+    /**
+     * Get the list of all cell addresses currently held in cache sorted by column and row
+     *
+     * @return    string[]
+     */
+    public function getSortedCellList();
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     * @return    void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent);
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return    boolean
+     */
+    public static function cacheMethodIsAvailable();
+}

+ 149 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Igbinary.php

@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_Igbinary
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_Igbinary extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            $this->cellCache[$this->currentObjectID] = igbinary_serialize($this->currentObject);
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }    //    function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }    //    function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        if (!isset($this->cellCache[$pCoord])) {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = igbinary_unserialize($this->cellCache[$pCoord]);
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }    //    function getCacheData()
+
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+    }    //    function unsetWorksheetCells()
+
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return    boolean
+     */
+    public static function cacheMethodIsAvailable()
+    {
+        if (!function_exists('igbinary_serialize')) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 308 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Memcache.php

@@ -0,0 +1,308 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_Memcache
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Prefix used to uniquely identify cache data for this worksheet
+     *
+     * @var string
+     */
+    private $cachePrefix = null;
+
+    /**
+     * Cache timeout
+     *
+     * @var integer
+     */
+    private $cacheTime = 600;
+
+    /**
+     * Memcache interface
+     *
+     * @var resource
+     */
+    private $memcache = null;
+
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            $obj = serialize($this->currentObject);
+            if (!$this->memcache->replace($this->cachePrefix . $this->currentObjectID . '.cache', $obj, null, $this->cacheTime)) {
+                if (!$this->memcache->add($this->cachePrefix . $this->currentObjectID . '.cache', $obj, null, $this->cacheTime)) {
+                    $this->__destruct();
+                    throw new PHPExcel_Exception("Failed to store cell {$this->currentObjectID} in MemCache");
+                }
+            }
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }    //    function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+        $this->cellCache[$pCoord] = true;
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }    //    function addCacheData()
+
+
+    /**
+     * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+     *
+     * @param    string        $pCoord        Coordinate address of the cell to check
+     * @return    boolean
+     * @return    boolean
+     */
+    public function isDataSet($pCoord)
+    {
+        //    Check if the requested entry is the current object, or exists in the cache
+        if (parent::isDataSet($pCoord)) {
+            if ($this->currentObjectID == $pCoord) {
+                return true;
+            }
+            //    Check if the requested entry still exists in Memcache
+            $success = $this->memcache->get($this->cachePrefix.$pCoord.'.cache');
+            if ($success === false) {
+                //    Entry no longer exists in Memcache, so clear it from the cache array
+                parent::deleteCacheData($pCoord);
+                throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
+            }
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        if (parent::isDataSet($pCoord)) {
+            $obj = $this->memcache->get($this->cachePrefix . $pCoord . '.cache');
+            if ($obj === false) {
+                //    Entry no longer exists in Memcache, so clear it from the cache array
+                parent::deleteCacheData($pCoord);
+                throw new PHPExcel_Exception("Cell entry {$pCoord} no longer exists in MemCache");
+            }
+        } else {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = unserialize($obj);
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to delete
+     * @throws    PHPExcel_Exception
+     */
+    public function deleteCacheData($pCoord)
+    {
+        //    Delete the entry from Memcache
+        $this->memcache->delete($this->cachePrefix . $pCoord . '.cache');
+
+        //    Delete the entry from our cell address array
+        parent::deleteCacheData($pCoord);
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     * @return    void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        parent::copyCellCollection($parent);
+        //    Get a new id for the new file name
+        $baseUnique = $this->getUniqueID();
+        $newCachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+        $cacheList = $this->getCellList();
+        foreach ($cacheList as $cellID) {
+            if ($cellID != $this->currentObjectID) {
+                $obj = $this->memcache->get($this->cachePrefix.$cellID.'.cache');
+                if ($obj === false) {
+                    //    Entry no longer exists in Memcache, so clear it from the cache array
+                    parent::deleteCacheData($cellID);
+                    throw new PHPExcel_Exception("Cell entry {$cellID} no longer exists in MemCache");
+                }
+                if (!$this->memcache->add($newCachePrefix . $cellID . '.cache', $obj, null, $this->cacheTime)) {
+                    $this->__destruct();
+                    throw new PHPExcel_Exception("Failed to store cell {$cellID} in MemCache");
+                }
+            }
+        }
+        $this->cachePrefix = $newCachePrefix;
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+
+        //    Flush the Memcache cache
+        $this->__destruct();
+
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+    }
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The worksheet for this cell collection
+     * @param    array of mixed        $arguments    Additional initialisation arguments
+     */
+    public function __construct(PHPExcel_Worksheet $parent, $arguments)
+    {
+        $memcacheServer = (isset($arguments['memcacheServer'])) ? $arguments['memcacheServer'] : 'localhost';
+        $memcachePort = (isset($arguments['memcachePort'])) ? $arguments['memcachePort'] : 11211;
+        $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
+
+        if (is_null($this->cachePrefix)) {
+            $baseUnique = $this->getUniqueID();
+            $this->cachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+
+            //    Set a new Memcache object and connect to the Memcache server
+            $this->memcache = new Memcache();
+            if (!$this->memcache->addServer($memcacheServer, $memcachePort, false, 50, 5, 5, true, array($this, 'failureCallback'))) {
+                throw new PHPExcel_Exception("Could not connect to MemCache server at {$memcacheServer}:{$memcachePort}");
+            }
+            $this->cacheTime = $cacheTime;
+
+            parent::__construct($parent);
+        }
+    }
+
+    /**
+     * Memcache error handler
+     *
+     * @param    string    $host        Memcache server
+     * @param    integer    $port        Memcache port
+     * @throws    PHPExcel_Exception
+     */
+    public function failureCallback($host, $port)
+    {
+        throw new PHPExcel_Exception("memcache {$host}:{$port} failed");
+    }
+
+    /**
+     * Destroy this cell collection
+     */
+    public function __destruct()
+    {
+        $cacheList = $this->getCellList();
+        foreach ($cacheList as $cellID) {
+            $this->memcache->delete($this->cachePrefix.$cellID . '.cache');
+        }
+    }
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return    boolean
+     */
+    public static function cacheMethodIsAvailable()
+    {
+        if (!function_exists('memcache_add')) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 118 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Memory.php

@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_Memory
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Dummy method callable from CacheBase, but unused by Memory cache
+     *
+     * @return    void
+     */
+    protected function storeData()
+    {
+    }
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        $this->cellCache[$pCoord] = $cell;
+
+        //    Set current entry to the new/updated entry
+        $this->currentObjectID = $pCoord;
+
+        return $cell;
+    }
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        //    Check if the entry that has been requested actually exists
+        if (!isset($this->cellCache[$pCoord])) {
+            $this->currentObjectID = null;
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+
+        //    Return requested entry
+        return $this->cellCache[$pCoord];
+    }
+
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        parent::copyCellCollection($parent);
+
+        $newCollection = array();
+        foreach ($this->cellCache as $k => &$cell) {
+            $newCollection[$k] = clone $cell;
+            $newCollection[$k]->attach($this);
+        }
+
+        $this->cellCache = $newCollection;
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     */
+    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) {
+            $cell->detach();
+            $this->cellCache[$k] = null;
+        }
+        unset($cell);
+
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+    }
+}

+ 133 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/MemoryGZip.php

@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_MemoryGZip
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            $this->cellCache[$this->currentObjectID] = gzdeflate(serialize($this->currentObject));
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        if (!isset($this->cellCache[$pCoord])) {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = unserialize(gzinflate($this->cellCache[$pCoord]));
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+    }
+}

+ 129 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/MemorySerialized.php

@@ -0,0 +1,129 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_MemorySerialized
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            $this->cellCache[$this->currentObjectID] = serialize($this->currentObject);
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        if (!isset($this->cellCache[$pCoord])) {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = unserialize($this->cellCache[$pCoord]);
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+    }
+}

+ 200 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/PHPTemp.php

@@ -0,0 +1,200 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_PHPTemp
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Name of the file for this cache
+     *
+     * @var string
+     */
+    private $fileHandle = null;
+
+    /**
+     * Memory limit to use before reverting to file cache
+     *
+     * @var integer
+     */
+    private $memoryCacheSize = null;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            fseek($this->fileHandle, 0, SEEK_END);
+
+            $this->cellCache[$this->currentObjectID] = array(
+                'ptr' => ftell($this->fileHandle),
+                'sz'  => fwrite($this->fileHandle, serialize($this->currentObject))
+            );
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        if (!isset($this->cellCache[$pCoord])) {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        fseek($this->fileHandle, $this->cellCache[$pCoord]['ptr']);
+        $this->currentObject = unserialize(fread($this->fileHandle, $this->cellCache[$pCoord]['sz']));
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     * @return    void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        parent::copyCellCollection($parent);
+        //    Open a new stream for the cell cache data
+        $newFileHandle = fopen('php://temp/maxmemory:' . $this->memoryCacheSize, 'a+');
+        //    Copy the existing cell cache data to the new stream
+        fseek($this->fileHandle, 0);
+        while (!feof($this->fileHandle)) {
+            fwrite($newFileHandle, fread($this->fileHandle, 1024));
+        }
+        $this->fileHandle = $newFileHandle;
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+
+        //    Close down the php://temp file
+        $this->__destruct();
+    }
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The worksheet for this cell collection
+     * @param    array of mixed        $arguments    Additional initialisation arguments
+     */
+    public function __construct(PHPExcel_Worksheet $parent, $arguments)
+    {
+        $this->memoryCacheSize = (isset($arguments['memoryCacheSize'])) ? $arguments['memoryCacheSize'] : '1MB';
+
+        parent::__construct($parent);
+        if (is_null($this->fileHandle)) {
+            $this->fileHandle = fopen('php://temp/maxmemory:' . $this->memoryCacheSize, 'a+');
+        }
+    }
+
+    /**
+     * Destroy this cell collection
+     */
+    public function __destruct()
+    {
+        if (!is_null($this->fileHandle)) {
+            fclose($this->fileHandle);
+        }
+        $this->fileHandle = null;
+    }
+}

+ 307 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/SQLite.php

@@ -0,0 +1,307 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_SQLite
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Database table name
+     *
+     * @var string
+     */
+    private $TableName = null;
+
+    /**
+     * Database handle
+     *
+     * @var resource
+     */
+    private $DBHandle = null;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            if (!$this->DBHandle->queryExec("INSERT OR REPLACE INTO kvp_".$this->TableName." VALUES('".$this->currentObjectID."','".sqlite_escape_string(serialize($this->currentObject))."')")) {
+                throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+            }
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        $query = "SELECT value FROM kvp_".$this->TableName." WHERE id='".$pCoord."'";
+        $cellResultSet = $this->DBHandle->query($query, SQLITE_ASSOC);
+        if ($cellResultSet === false) {
+            throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+        } elseif ($cellResultSet->numRows() == 0) {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+
+        $cellResult = $cellResultSet->fetchSingle();
+        $this->currentObject = unserialize($cellResult);
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+    /**
+     * Is a value set for an indexed cell?
+     *
+     * @param    string        $pCoord        Coordinate address of the cell to check
+     * @return    boolean
+     */
+    public function isDataSet($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return true;
+        }
+
+        //    Check if the requested entry exists in the cache
+        $query = "SELECT id FROM kvp_".$this->TableName." WHERE id='".$pCoord."'";
+        $cellResultSet = $this->DBHandle->query($query, SQLITE_ASSOC);
+        if ($cellResultSet === false) {
+            throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+        } elseif ($cellResultSet->numRows() == 0) {
+            //    Return null if requested entry doesn't exist in cache
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to delete
+     * @throws    PHPExcel_Exception
+     */
+    public function deleteCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            $this->currentObject->detach();
+            $this->currentObjectID = $this->currentObject = null;
+        }
+
+        //    Check if the requested entry exists in the cache
+        $query = "DELETE FROM kvp_".$this->TableName." WHERE id='".$pCoord."'";
+        if (!$this->DBHandle->queryExec($query)) {
+            throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+        }
+
+        $this->currentCellIsDirty = false;
+    }
+
+    /**
+     * Move a cell object from one address to another
+     *
+     * @param    string        $fromAddress    Current address of the cell to move
+     * @param    string        $toAddress        Destination address of the cell to move
+     * @return    boolean
+     */
+    public function moveCell($fromAddress, $toAddress)
+    {
+        if ($fromAddress === $this->currentObjectID) {
+            $this->currentObjectID = $toAddress;
+        }
+
+        $query = "DELETE FROM kvp_".$this->TableName." WHERE id='".$toAddress."'";
+        $result = $this->DBHandle->exec($query);
+        if ($result === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+
+        $query = "UPDATE kvp_".$this->TableName." SET id='".$toAddress."' WHERE id='".$fromAddress."'";
+        $result = $this->DBHandle->exec($query);
+        if ($result === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+
+        return true;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return    string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        $query = "SELECT id FROM kvp_".$this->TableName;
+        $cellIdsResult = $this->DBHandle->unbufferedQuery($query, SQLITE_ASSOC);
+        if ($cellIdsResult === false) {
+            throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+        }
+
+        $cellKeys = array();
+        foreach ($cellIdsResult as $row) {
+            $cellKeys[] = $row['id'];
+        }
+
+        return $cellKeys;
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     * @return    void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        $this->currentCellIsDirty;
+        $this->storeData();
+
+        //    Get a new id for the new table name
+        $tableName = str_replace('.', '_', $this->getUniqueID());
+        if (!$this->DBHandle->queryExec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
+            AS SELECT * FROM kvp_'.$this->TableName)
+        ) {
+            throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+        }
+
+        //    Copy the existing cell cache file
+        $this->TableName = $tableName;
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+
+        //    Close down the temporary cache file
+        $this->__destruct();
+    }
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The worksheet for this cell collection
+     */
+    public function __construct(PHPExcel_Worksheet $parent)
+    {
+        parent::__construct($parent);
+        if (is_null($this->DBHandle)) {
+            $this->TableName = str_replace('.', '_', $this->getUniqueID());
+            $_DBName = ':memory:';
+
+            $this->DBHandle = new SQLiteDatabase($_DBName);
+            if ($this->DBHandle === false) {
+                throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+            }
+            if (!$this->DBHandle->queryExec('CREATE TABLE kvp_'.$this->TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) {
+                throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+            }
+        }
+    }
+
+    /**
+     * Destroy this cell collection
+     */
+    public function __destruct()
+    {
+        if (!is_null($this->DBHandle)) {
+            $this->DBHandle->queryExec('DROP TABLE kvp_'.$this->TableName);
+        }
+        $this->DBHandle = null;
+    }
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return    boolean
+     */
+    public static function cacheMethodIsAvailable()
+    {
+        if (!function_exists('sqlite_open')) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 346 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/SQLite3.php

@@ -0,0 +1,346 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_SQLite3
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Database table name
+     *
+     * @var string
+     */
+    private $TableName = null;
+
+    /**
+     * Database handle
+     *
+     * @var resource
+     */
+    private $DBHandle = null;
+
+    /**
+     * Prepared statement for a SQLite3 select query
+     *
+     * @var SQLite3Stmt
+     */
+    private $selectQuery;
+
+    /**
+     * Prepared statement for a SQLite3 insert query
+     *
+     * @var SQLite3Stmt
+     */
+    private $insertQuery;
+
+    /**
+     * Prepared statement for a SQLite3 update query
+     *
+     * @var SQLite3Stmt
+     */
+    private $updateQuery;
+
+    /**
+     * Prepared statement for a SQLite3 delete query
+     *
+     * @var SQLite3Stmt
+     */
+    private $deleteQuery;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            $this->insertQuery->bindValue('id', $this->currentObjectID, SQLITE3_TEXT);
+            $this->insertQuery->bindValue('data', serialize($this->currentObject), SQLITE3_BLOB);
+            $result = $this->insertQuery->execute();
+            if ($result === false) {
+                throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+            }
+            $this->currentCellIsDirty = false;
+        }
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param     string             $pCoord        Coordinate of the cell
+     * @throws     PHPExcel_Exception
+     * @return     PHPExcel_Cell     Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        $this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
+        $cellResult = $this->selectQuery->execute();
+        if ($cellResult === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+        $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
+        if ($cellData === false) {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+
+        $this->currentObject = unserialize($cellData['value']);
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+    /**
+     *    Is a value set for an indexed cell?
+     *
+     * @param    string        $pCoord        Coordinate address of the cell to check
+     * @return    boolean
+     */
+    public function isDataSet($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return true;
+        }
+
+        //    Check if the requested entry exists in the cache
+        $this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
+        $cellResult = $this->selectQuery->execute();
+        if ($cellResult === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+        $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
+
+        return ($cellData === false) ? false : true;
+    }
+
+    /**
+     *    Delete a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to delete
+     * @throws    PHPExcel_Exception
+     */
+    public function deleteCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            $this->currentObject->detach();
+            $this->currentObjectID = $this->currentObject = null;
+        }
+
+        //    Check if the requested entry exists in the cache
+        $this->deleteQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
+        $result = $this->deleteQuery->execute();
+        if ($result === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+
+        $this->currentCellIsDirty = false;
+    }
+
+    /**
+     * Move a cell object from one address to another
+     *
+     * @param    string        $fromAddress    Current address of the cell to move
+     * @param    string        $toAddress        Destination address of the cell to move
+     * @return    boolean
+     */
+    public function moveCell($fromAddress, $toAddress)
+    {
+        if ($fromAddress === $this->currentObjectID) {
+            $this->currentObjectID = $toAddress;
+        }
+
+        $this->deleteQuery->bindValue('id', $toAddress, SQLITE3_TEXT);
+        $result = $this->deleteQuery->execute();
+        if ($result === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+
+        $this->updateQuery->bindValue('toid', $toAddress, SQLITE3_TEXT);
+        $this->updateQuery->bindValue('fromid', $fromAddress, SQLITE3_TEXT);
+        $result = $this->updateQuery->execute();
+        if ($result === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+
+        return true;
+    }
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return    string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        $query = "SELECT id FROM kvp_".$this->TableName;
+        $cellIdsResult = $this->DBHandle->query($query);
+        if ($cellIdsResult === false) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+
+        $cellKeys = array();
+        while ($row = $cellIdsResult->fetchArray(SQLITE3_ASSOC)) {
+            $cellKeys[] = $row['id'];
+        }
+
+        return $cellKeys;
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     * @return    void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        $this->currentCellIsDirty;
+        $this->storeData();
+
+        //    Get a new id for the new table name
+        $tableName = str_replace('.', '_', $this->getUniqueID());
+        if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
+            AS SELECT * FROM kvp_'.$this->TableName)
+        ) {
+            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+        }
+
+        //    Copy the existing cell cache file
+        $this->TableName = $tableName;
+    }
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+
+        //    Close down the temporary cache file
+        $this->__destruct();
+    }
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The worksheet for this cell collection
+     */
+    public function __construct(PHPExcel_Worksheet $parent)
+    {
+        parent::__construct($parent);
+        if (is_null($this->DBHandle)) {
+            $this->TableName = str_replace('.', '_', $this->getUniqueID());
+            $_DBName = ':memory:';
+
+            $this->DBHandle = new SQLite3($_DBName);
+            if ($this->DBHandle === false) {
+                throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+            }
+            if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$this->TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) {
+                throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+            }
+        }
+
+        $this->selectQuery = $this->DBHandle->prepare("SELECT value FROM kvp_".$this->TableName." WHERE id = :id");
+        $this->insertQuery = $this->DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->TableName." VALUES(:id,:data)");
+        $this->updateQuery = $this->DBHandle->prepare("UPDATE kvp_".$this->TableName." SET id=:toId WHERE id=:fromId");
+        $this->deleteQuery = $this->DBHandle->prepare("DELETE FROM kvp_".$this->TableName." WHERE id = :id");
+    }
+
+    /**
+     * Destroy this cell collection
+     */
+    public function __destruct()
+    {
+        if (!is_null($this->DBHandle)) {
+            $this->DBHandle->exec('DROP TABLE kvp_'.$this->TableName);
+            $this->DBHandle->close();
+        }
+        $this->DBHandle = null;
+    }
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return    boolean
+     */
+    public static function cacheMethodIsAvailable()
+    {
+        if (!class_exists('SQLite3', false)) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 289 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorage/Wincache.php

@@ -0,0 +1,289 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorage_Wincache
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache
+{
+    /**
+     * Prefix used to uniquely identify cache data for this worksheet
+     *
+     * @var string
+     */
+    private $cachePrefix = null;
+
+    /**
+     * Cache timeout
+     *
+     * @var integer
+     */
+    private $cacheTime = 600;
+
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+     * @return    void
+     * @throws    PHPExcel_Exception
+     */
+    protected function storeData()
+    {
+        if ($this->currentCellIsDirty && !empty($this->currentObjectID)) {
+            $this->currentObject->detach();
+
+            $obj = serialize($this->currentObject);
+            if (wincache_ucache_exists($this->cachePrefix.$this->currentObjectID.'.cache')) {
+                if (!wincache_ucache_set($this->cachePrefix.$this->currentObjectID.'.cache', $obj, $this->cacheTime)) {
+                    $this->__destruct();
+                    throw new PHPExcel_Exception('Failed to store cell '.$this->currentObjectID.' in WinCache');
+                }
+            } else {
+                if (!wincache_ucache_add($this->cachePrefix.$this->currentObjectID.'.cache', $obj, $this->cacheTime)) {
+                    $this->__destruct();
+                    throw new PHPExcel_Exception('Failed to store cell '.$this->currentObjectID.' in WinCache');
+                }
+            }
+            $this->currentCellIsDirty = false;
+        }
+
+        $this->currentObjectID = $this->currentObject = null;
+    }
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to update
+     * @param    PHPExcel_Cell    $cell        Cell to update
+     * @return    PHPExcel_Cell
+     * @throws    PHPExcel_Exception
+     */
+    public function addCacheData($pCoord, PHPExcel_Cell $cell)
+    {
+        if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+            $this->storeData();
+        }
+        $this->cellCache[$pCoord] = true;
+
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = $cell;
+        $this->currentCellIsDirty = true;
+
+        return $cell;
+    }
+
+    /**
+     * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+     *
+     * @param    string        $pCoord        Coordinate address of the cell to check
+     * @return    boolean
+     */
+    public function isDataSet($pCoord)
+    {
+        //    Check if the requested entry is the current object, or exists in the cache
+        if (parent::isDataSet($pCoord)) {
+            if ($this->currentObjectID == $pCoord) {
+                return true;
+            }
+            //    Check if the requested entry still exists in cache
+            $success = wincache_ucache_exists($this->cachePrefix.$pCoord.'.cache');
+            if ($success === false) {
+                //    Entry no longer exists in Wincache, so clear it from the cache array
+                parent::deleteCacheData($pCoord);
+                throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
+            }
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param    string            $pCoord        Coordinate of the cell
+     * @throws    PHPExcel_Exception
+     * @return    PHPExcel_Cell    Cell that was found, or null if not found
+     */
+    public function getCacheData($pCoord)
+    {
+        if ($pCoord === $this->currentObjectID) {
+            return $this->currentObject;
+        }
+        $this->storeData();
+
+        //    Check if the entry that has been requested actually exists
+        $obj = null;
+        if (parent::isDataSet($pCoord)) {
+            $success = false;
+            $obj = wincache_ucache_get($this->cachePrefix.$pCoord.'.cache', $success);
+            if ($success === false) {
+                //    Entry no longer exists in WinCache, so clear it from the cache array
+                parent::deleteCacheData($pCoord);
+                throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
+            }
+        } else {
+            //    Return null if requested entry doesn't exist in cache
+            return null;
+        }
+
+        //    Set current entry to the requested entry
+        $this->currentObjectID = $pCoord;
+        $this->currentObject = unserialize($obj);
+        //    Re-attach this as the cell's parent
+        $this->currentObject->attach($this);
+
+        //    Return requested entry
+        return $this->currentObject;
+    }
+
+
+    /**
+     * Get a list of all cell addresses currently held in cache
+     *
+     * @return  string[]
+     */
+    public function getCellList()
+    {
+        if ($this->currentObjectID !== null) {
+            $this->storeData();
+        }
+
+        return parent::getCellList();
+    }
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param    string            $pCoord        Coordinate address of the cell to delete
+     * @throws    PHPExcel_Exception
+     */
+    public function deleteCacheData($pCoord)
+    {
+        //    Delete the entry from Wincache
+        wincache_ucache_delete($this->cachePrefix.$pCoord.'.cache');
+
+        //    Delete the entry from our cell address array
+        parent::deleteCacheData($pCoord);
+    }
+
+    /**
+     * Clone the cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The new worksheet
+     * @return    void
+     */
+    public function copyCellCollection(PHPExcel_Worksheet $parent)
+    {
+        parent::copyCellCollection($parent);
+        //    Get a new id for the new file name
+        $baseUnique = $this->getUniqueID();
+        $newCachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+        $cacheList = $this->getCellList();
+        foreach ($cacheList as $cellID) {
+            if ($cellID != $this->currentObjectID) {
+                $success = false;
+                $obj = wincache_ucache_get($this->cachePrefix.$cellID.'.cache', $success);
+                if ($success === false) {
+                    //    Entry no longer exists in WinCache, so clear it from the cache array
+                    parent::deleteCacheData($cellID);
+                    throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in Wincache');
+                }
+                if (!wincache_ucache_add($newCachePrefix.$cellID.'.cache', $obj, $this->cacheTime)) {
+                    $this->__destruct();
+                    throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in Wincache');
+                }
+            }
+        }
+        $this->cachePrefix = $newCachePrefix;
+    }
+
+
+    /**
+     * Clear the cell collection and disconnect from our parent
+     *
+     * @return    void
+     */
+    public function unsetWorksheetCells()
+    {
+        if (!is_null($this->currentObject)) {
+            $this->currentObject->detach();
+            $this->currentObject = $this->currentObjectID = null;
+        }
+
+        //    Flush the WinCache cache
+        $this->__destruct();
+
+        $this->cellCache = array();
+
+        //    detach ourself from the worksheet, so that it can then delete this object successfully
+        $this->parent = null;
+    }
+
+    /**
+     * Initialise this new cell collection
+     *
+     * @param    PHPExcel_Worksheet    $parent        The worksheet for this cell collection
+     * @param    array of mixed        $arguments    Additional initialisation arguments
+     */
+    public function __construct(PHPExcel_Worksheet $parent, $arguments)
+    {
+        $cacheTime    = (isset($arguments['cacheTime']))    ? $arguments['cacheTime']    : 600;
+
+        if (is_null($this->cachePrefix)) {
+            $baseUnique = $this->getUniqueID();
+            $this->cachePrefix = substr(md5($baseUnique), 0, 8).'.';
+            $this->cacheTime = $cacheTime;
+
+            parent::__construct($parent);
+        }
+    }
+
+    /**
+     * Destroy this cell collection
+     */
+    public function __destruct()
+    {
+        $cacheList = $this->getCellList();
+        foreach ($cacheList as $cellID) {
+            wincache_ucache_delete($this->cachePrefix.$cellID.'.cache');
+        }
+    }
+
+    /**
+     * Identify whether the caching method is currently available
+     * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+     *
+     * @return    boolean
+     */
+    public static function cacheMethodIsAvailable()
+    {
+        if (!function_exists('wincache_ucache_add')) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 231 - 0
backend/RTP/extend/excel/PHPExcel/CachedObjectStorageFactory.php

@@ -0,0 +1,231 @@
+<?php
+
+/**
+ * PHPExcel_CachedObjectStorageFactory
+ *
+ * Copyright (c) 2006 - 2015 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_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CachedObjectStorageFactory
+{
+    const cache_in_memory               = 'Memory';
+    const cache_in_memory_gzip          = 'MemoryGZip';
+    const cache_in_memory_serialized    = 'MemorySerialized';
+    const cache_igbinary                = 'Igbinary';
+    const cache_to_discISAM             = 'DiscISAM';
+    const cache_to_apc                  = 'APC';
+    const cache_to_memcache             = 'Memcache';
+    const cache_to_phpTemp              = 'PHPTemp';
+    const cache_to_wincache             = 'Wincache';
+    const cache_to_sqlite               = 'SQLite';
+    const cache_to_sqlite3              = 'SQLite3';
+
+    /**
+     * Name of the method used for cell cacheing
+     *
+     * @var string
+     */
+    private static $cacheStorageMethod = null;
+
+    /**
+     * Name of the class used for cell cacheing
+     *
+     * @var string
+     */
+    private static $cacheStorageClass = null;
+
+    /**
+     * List of all possible cache storage methods
+     *
+     * @var string[]
+     */
+    private static $storageMethods = array(
+        self::cache_in_memory,
+        self::cache_in_memory_gzip,
+        self::cache_in_memory_serialized,
+        self::cache_igbinary,
+        self::cache_to_phpTemp,
+        self::cache_to_discISAM,
+        self::cache_to_apc,
+        self::cache_to_memcache,
+        self::cache_to_wincache,
+        self::cache_to_sqlite,
+        self::cache_to_sqlite3,
+    );
+
+    /**
+     * Default arguments for each cache storage method
+     *
+     * @var array of mixed array
+     */
+    private static $storageMethodDefaultParameters = array(
+        self::cache_in_memory               => array(
+                                                    ),
+        self::cache_in_memory_gzip          => array(
+                                                    ),
+        self::cache_in_memory_serialized    => array(
+                                                    ),
+        self::cache_igbinary                => array(
+                                                    ),
+        self::cache_to_phpTemp              => array( 'memoryCacheSize' => '1MB'
+                                                    ),
+        self::cache_to_discISAM             => array( 'dir'             => null
+                                                    ),
+        self::cache_to_apc                  => array( 'cacheTime'       => 600
+                                                    ),
+        self::cache_to_memcache             => array( 'memcacheServer'  => 'localhost',
+                                                      'memcachePort'    => 11211,
+                                                      'cacheTime'       => 600
+                                                    ),
+        self::cache_to_wincache             => array( 'cacheTime'       => 600
+                                                    ),
+        self::cache_to_sqlite               => array(
+                                                    ),
+        self::cache_to_sqlite3              => array(
+                                                    ),
+    );
+
+    /**
+     * Arguments for the active cache storage method
+     *
+     * @var array of mixed array
+     */
+    private static $storageMethodParameters = array();
+
+    /**
+     * Return the current cache storage method
+     *
+     * @return string|null
+     **/
+    public static function getCacheStorageMethod()
+    {
+        return self::$cacheStorageMethod;
+    }
+
+    /**
+     * Return the current cache storage class
+     *
+     * @return PHPExcel_CachedObjectStorage_ICache|null
+     **/
+    public static function getCacheStorageClass()
+    {
+        return self::$cacheStorageClass;
+    }
+
+    /**
+     * Return the list of all possible cache storage methods
+     *
+     * @return string[]
+     **/
+    public static function getAllCacheStorageMethods()
+    {
+        return self::$storageMethods;
+    }
+
+    /**
+     * Return the list of all available cache storage methods
+     *
+     * @return string[]
+     **/
+    public static function getCacheStorageMethods()
+    {
+        $activeMethods = array();
+        foreach (self::$storageMethods as $storageMethod) {
+            $cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $storageMethod;
+            if (call_user_func(array($cacheStorageClass, 'cacheMethodIsAvailable'))) {
+                $activeMethods[] = $storageMethod;
+            }
+        }
+        return $activeMethods;
+    }
+
+    /**
+     * Identify the cache storage method to use
+     *
+     * @param    string            $method        Name of the method to use for cell cacheing
+     * @param    array of mixed    $arguments    Additional arguments to pass to the cell caching class
+     *                                        when instantiating
+     * @return boolean
+     **/
+    public static function initialize($method = self::cache_in_memory, $arguments = array())
+    {
+        if (!in_array($method, self::$storageMethods)) {
+            return false;
+        }
+
+        $cacheStorageClass = 'PHPExcel_CachedObjectStorage_'.$method;
+        if (!call_user_func(array( $cacheStorageClass,
+                                   'cacheMethodIsAvailable'))) {
+            return false;
+        }
+
+        self::$storageMethodParameters[$method] = self::$storageMethodDefaultParameters[$method];
+        foreach ($arguments as $k => $v) {
+            if (array_key_exists($k, self::$storageMethodParameters[$method])) {
+                self::$storageMethodParameters[$method][$k] = $v;
+            }
+        }
+
+        if (self::$cacheStorageMethod === null) {
+            self::$cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $method;
+            self::$cacheStorageMethod = $method;
+        }
+        return true;
+    }
+
+    /**
+     * Initialise the cache storage
+     *
+     * @param    PHPExcel_Worksheet     $parent        Enable cell caching for this worksheet
+     * @return    PHPExcel_CachedObjectStorage_ICache
+     **/
+    public static function getInstance(PHPExcel_Worksheet $parent)
+    {
+        $cacheMethodIsAvailable = true;
+        if (self::$cacheStorageMethod === null) {
+            $cacheMethodIsAvailable = self::initialize();
+        }
+
+        if ($cacheMethodIsAvailable) {
+            $instance = new self::$cacheStorageClass(
+                $parent,
+                self::$storageMethodParameters[self::$cacheStorageMethod]
+            );
+            if ($instance !== null) {
+                return $instance;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Clear the cache storage
+     *
+     **/
+    public static function finalize()
+    {
+        self::$cacheStorageMethod = null;
+        self::$cacheStorageClass = null;
+        self::$storageMethodParameters = array();
+    }
+}

+ 94 - 0
backend/RTP/extend/excel/PHPExcel/CalcEngine/CyclicReferenceStack.php

@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * PHPExcel_CalcEngine_CyclicReferenceStack
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CalcEngine_CyclicReferenceStack
+{
+    /**
+     *  The call stack for calculated cells
+     *
+     *  @var mixed[]
+     */
+    private $stack = array();
+
+    /**
+     * Return the number of entries on the stack
+     *
+     * @return  integer
+     */
+    public function count()
+    {
+        return count($this->stack);
+    }
+
+    /**
+     * Push a new entry onto the stack
+     *
+     * @param  mixed  $value
+     */
+    public function push($value)
+    {
+        $this->stack[$value] = $value;
+    }
+
+    /**
+     * Pop the last entry from the stack
+     *
+     * @return  mixed
+     */
+    public function pop()
+    {
+        return array_pop($this->stack);
+    }
+
+    /**
+     * Test to see if a specified entry exists on the stack
+     *
+     * @param  mixed  $value  The value to test
+     */
+    public function onStack($value)
+    {
+        return isset($this->stack[$value]);
+    }
+
+    /**
+     * Clear the stack
+     */
+    public function clear()
+    {
+        $this->stack = array();
+    }
+
+    /**
+     * Return an array of all entries on the stack
+     *
+     * @return  mixed[]
+     */
+    public function showStack()
+    {
+        return $this->stack;
+    }
+}

+ 151 - 0
backend/RTP/extend/excel/PHPExcel/CalcEngine/Logger.php

@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * PHPExcel_CalcEngine_Logger
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_CalcEngine_Logger
+{
+    /**
+     * Flag to determine whether a debug log should be generated by the calculation engine
+     *        If true, then a debug log will be generated
+     *        If false, then a debug log will not be generated
+     *
+     * @var boolean
+     */
+    private $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
+     *
+     * @var boolean
+     */
+    private $echoDebugLog = false;
+
+    /**
+     * The debug log generated by the calculation engine
+     *
+     * @var string[]
+     */
+    private $debugLog = array();
+
+    /**
+     * The calculation engine cell reference stack
+     *
+     * @var PHPExcel_CalcEngine_CyclicReferenceStack
+     */
+    private $cellStack;
+
+    /**
+     * Instantiate a Calculation engine logger
+     *
+     * @param  PHPExcel_CalcEngine_CyclicReferenceStack $stack
+     */
+    public function __construct(PHPExcel_CalcEngine_CyclicReferenceStack $stack)
+    {
+        $this->cellStack = $stack;
+    }
+
+    /**
+     * Enable/Disable Calculation engine logging
+     *
+     * @param  boolean $pValue
+     */
+    public function setWriteDebugLog($pValue = false)
+    {
+        $this->writeDebugLog = $pValue;
+    }
+
+    /**
+     * Return whether calculation engine logging is enabled or disabled
+     *
+     * @return  boolean
+     */
+    public function getWriteDebugLog()
+    {
+        return $this->writeDebugLog;
+    }
+
+    /**
+     * Enable/Disable echoing of debug log information
+     *
+     * @param  boolean $pValue
+     */
+    public function setEchoDebugLog($pValue = false)
+    {
+        $this->echoDebugLog = $pValue;
+    }
+
+    /**
+     * Return whether echoing of debug log information is enabled or disabled
+     *
+     * @return  boolean
+     */
+    public function getEchoDebugLog()
+    {
+        return $this->echoDebugLog;
+    }
+
+    /**
+     * Write an entry to the calculation engine debug log
+     */
+    public function writeDebugLog()
+    {
+        //    Only write the debug log if logging is enabled
+        if ($this->writeDebugLog) {
+            $message = implode(func_get_args());
+            $cellReference = implode(' -> ', $this->cellStack->showStack());
+            if ($this->echoDebugLog) {
+                echo $cellReference,
+                    ($this->cellStack->count() > 0 ? ' => ' : ''),
+                    $message,
+                    PHP_EOL;
+            }
+            $this->debugLog[] = $cellReference .
+                ($this->cellStack->count() > 0 ? ' => ' : '') .
+                $message;
+        }
+    }
+
+    /**
+     * Clear the calculation engine debug log
+     */
+    public function clearLog()
+    {
+        $this->debugLog = array();
+    }
+
+    /**
+     * Return the calculation engine debug log
+     *
+     * @return  string[]
+     */
+    public function getLog()
+    {
+        return $this->debugLog;
+    }
+}

File diff suppressed because it is too large
+ 4391 - 0
backend/RTP/extend/excel/PHPExcel/Calculation.php


+ 676 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Database.php

@@ -0,0 +1,676 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Calculation_Database
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_Database
+{
+    /**
+     * fieldExtract
+     *
+     * Extracts the column ID to use for the data field.
+     *
+     * @access    private
+     * @param    mixed[]        $database        The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    mixed        $field            Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @return    string|NULL
+     *
+     */
+    private static function fieldExtract($database, $field)
+    {
+        $field = strtoupper(PHPExcel_Calculation_Functions::flattenSingleValue($field));
+        $fieldNames = array_map('strtoupper', array_shift($database));
+
+        if (is_numeric($field)) {
+            $keys = array_keys($fieldNames);
+            return $keys[$field-1];
+        }
+        $key = array_search($field, $fieldNames);
+        return ($key) ? $key : null;
+    }
+
+    /**
+     * filter
+     *
+     * Parses the selection criteria, extracts the database rows that match those criteria, and
+     * returns that subset of rows.
+     *
+     * @access    private
+     * @param    mixed[]        $database        The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    mixed[]        $criteria        The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    array of mixed
+     *
+     */
+    private static function filter($database, $criteria)
+    {
+        $fieldNames = array_shift($database);
+        $criteriaNames = array_shift($criteria);
+
+        //    Convert the criteria into a set of AND/OR conditions with [:placeholders]
+        $testConditions = $testValues = array();
+        $testConditionsCount = 0;
+        foreach ($criteriaNames as $key => $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;
+    }
+
+
+    private static function getFilteredColumn($database, $field, $criteria)
+    {
+        //    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 $colData;
+    }
+
+    /**
+     * DAVERAGE
+     *
+     * Averages the values in a column of a list or database that match conditions you specify.
+     *
+     * Excel Function:
+     *        DAVERAGE(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DAVERAGE($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::AVERAGE(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DCOUNT
+     *
+     * Counts the cells that contain numbers in a column of a list or database that match conditions
+     * that you specify.
+     *
+     * Excel Function:
+     *        DCOUNT(database,[field],criteria)
+     *
+     * Excel Function:
+     *        DAVERAGE(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    integer
+     *
+     * @TODO    The field argument is optional. If field is omitted, DCOUNT counts all records in the
+     *            database that match the criteria.
+     *
+     */
+    public static function DCOUNT($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::COUNT(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DCOUNTA
+     *
+     * Counts the nonblank cells in a column of a list or database that match conditions that you specify.
+     *
+     * Excel Function:
+     *        DCOUNTA(database,[field],criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    integer
+     *
+     * @TODO    The field argument is optional. If field is omitted, DCOUNTA counts all records in the
+     *            database that match the criteria.
+     *
+     */
+    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(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DGET
+     *
+     * Extracts a single value from a column of a list or database that matches conditions that you
+     * specify.
+     *
+     * Excel Function:
+     *        DGET(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    mixed
+     *
+     */
+    public static function DGET($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        $colData = self::getFilteredColumn($database, $field, $criteria);
+        if (count($colData) > 1) {
+            return PHPExcel_Calculation_Functions::NaN();
+        }
+
+        return $colData[0];
+    }
+
+
+    /**
+     * DMAX
+     *
+     * Returns the largest number in a column of a list or database that matches conditions you that
+     * specify.
+     *
+     * Excel Function:
+     *        DMAX(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DMAX($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::MAX(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DMIN
+     *
+     * Returns the smallest number in a column of a list or database that matches conditions you that
+     * specify.
+     *
+     * Excel Function:
+     *        DMIN(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DMIN($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::MIN(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DPRODUCT
+     *
+     * Multiplies the values in a column of a list or database that match conditions that you specify.
+     *
+     * Excel Function:
+     *        DPRODUCT(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DPRODUCT($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_MathTrig::PRODUCT(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DSTDEV
+     *
+     * Estimates the standard deviation of a population based on a sample by using the numbers in a
+     * column of a list or database that match conditions that you specify.
+     *
+     * Excel Function:
+     *        DSTDEV(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DSTDEV($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::STDEV(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DSTDEVP
+     *
+     * Calculates the standard deviation of a population based on the entire population by using the
+     * numbers in a column of a list or database that match conditions that you specify.
+     *
+     * Excel Function:
+     *        DSTDEVP(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DSTDEVP($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::STDEVP(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DSUM
+     *
+     * Adds the numbers in a column of a list or database that match conditions that you specify.
+     *
+     * Excel Function:
+     *        DSUM(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DSUM($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_MathTrig::SUM(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DVAR
+     *
+     * Estimates the variance of a population based on a sample by using the numbers in a column
+     * of a list or database that match conditions that you specify.
+     *
+     * Excel Function:
+     *        DVAR(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DVAR($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::VARFunc(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+
+
+    /**
+     * DVARP
+     *
+     * Calculates the variance of a population based on the entire population by using the numbers
+     * in a column of a list or database that match conditions that you specify.
+     *
+     * Excel Function:
+     *        DVARP(database,field,criteria)
+     *
+     * @access    public
+     * @category Database Functions
+     * @param    mixed[]            $database    The range of cells that makes up the list or database.
+     *                                        A database is a list of related data in which rows of related
+     *                                        information are records, and columns of data are fields. The
+     *                                        first row of the list contains labels for each column.
+     * @param    string|integer    $field        Indicates which column is used in the function. Enter the
+     *                                        column label enclosed between double quotation marks, such as
+     *                                        "Age" or "Yield," or a number (without quotation marks) that
+     *                                        represents the position of the column within the list: 1 for
+     *                                        the first column, 2 for the second column, and so on.
+     * @param    mixed[]            $criteria    The range of cells that contains the conditions you specify.
+     *                                        You can use any range for the criteria argument, as long as it
+     *                                        includes at least one column label and at least one cell below
+     *                                        the column label in which you specify a condition for the
+     *                                        column.
+     * @return    float
+     *
+     */
+    public static function DVARP($database, $field, $criteria)
+    {
+        $field = self::fieldExtract($database, $field);
+        if (is_null($field)) {
+            return null;
+        }
+
+        // Return
+        return PHPExcel_Calculation_Statistical::VARP(
+            self::getFilteredColumn($database, $field, $criteria)
+        );
+    }
+}

File diff suppressed because it is too large
+ 1553 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/DateTime.php


File diff suppressed because it is too large
+ 2650 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Engineering.php


+ 46 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Exception.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * PHPExcel_Calculation_Exception
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_Exception extends PHPExcel_Exception
+{
+    /**
+     * Error handler callback
+     *
+     * @param mixed $code
+     * @param mixed $string
+     * @param mixed $file
+     * @param mixed $line
+     * @param mixed $context
+     */
+    public static function errorHandlerCallback($code, $string, $file, $line, $context)
+    {
+        $e = new self($string, $code);
+        $e->line = $line;
+        $e->file = $file;
+        throw $e;
+    }
+}

+ 45 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/ExceptionHandler.php

@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * PHPExcel_Calculation_ExceptionHandler
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_ExceptionHandler
+{
+    /**
+     * Register errorhandler
+     */
+    public function __construct()
+    {
+        set_error_handler(array('PHPExcel_Calculation_Exception', 'errorHandlerCallback'), E_ALL);
+    }
+
+    /**
+     * Unregister errorhandler
+     */
+    public function __destruct()
+    {
+        restore_error_handler();
+    }
+}

File diff suppressed because it is too large
+ 2359 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Financial.php


+ 622 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/FormulaParser.php

@@ -0,0 +1,622 @@
+<?php
+
+/*
+PARTLY BASED ON:
+    Copyright (c) 2007 E. W. Bachtal, Inc.
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+    and associated documentation files (the "Software"), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+      The above copyright notice and this permission notice shall be included in all copies or substantial
+      portions of the Software.
+
+    The software is provided "as is", without warranty of any kind, express or implied, including but not
+    limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In
+    no event shall the authors or copyright holders be liable for any claim, damages or other liability,
+    whether in an action of contract, tort or otherwise, arising from, out of or in connection with the
+    software or the use or other dealings in the software.
+
+    http://ewbi.blogs.com/develops/2007/03/excel_formula_p.html
+    http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html
+*/
+
+/**
+ * PHPExcel_Calculation_FormulaParser
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+
+
+class PHPExcel_Calculation_FormulaParser
+{
+    /* Character constants */
+    const QUOTE_DOUBLE  = '"';
+    const QUOTE_SINGLE  = '\'';
+    const BRACKET_CLOSE = ']';
+    const BRACKET_OPEN  = '[';
+    const BRACE_OPEN    = '{';
+    const BRACE_CLOSE   = '}';
+    const PAREN_OPEN    = '(';
+    const PAREN_CLOSE   = ')';
+    const SEMICOLON     = ';';
+    const WHITESPACE    = ' ';
+    const COMMA         = ',';
+    const ERROR_START   = '#';
+
+    const OPERATORS_SN             = "+-";
+    const OPERATORS_INFIX         = "+-*/^&=><";
+    const OPERATORS_POSTFIX     = "%";
+
+    /**
+     * Formula
+     *
+     * @var string
+     */
+    private $formula;
+
+    /**
+     * Tokens
+     *
+     * @var PHPExcel_Calculation_FormulaToken[]
+     */
+    private $tokens = array();
+
+    /**
+     * Create a new PHPExcel_Calculation_FormulaParser
+     *
+     * @param     string        $pFormula    Formula to parse
+     * @throws     PHPExcel_Calculation_Exception
+     */
+    public function __construct($pFormula = '')
+    {
+        // Check parameters
+        if (is_null($pFormula)) {
+            throw new PHPExcel_Calculation_Exception("Invalid parameter passed: formula");
+        }
+
+        // Initialise values
+        $this->formula = trim($pFormula);
+        // Parse!
+        $this->parseToTokens();
+    }
+
+    /**
+     * Get Formula
+     *
+     * @return string
+     */
+    public function getFormula()
+    {
+        return $this->formula;
+    }
+
+    /**
+     * Get Token
+     *
+     * @param     int        $pId    Token id
+     * @return    string
+     * @throws  PHPExcel_Calculation_Exception
+     */
+    public function getToken($pId = 0)
+    {
+        if (isset($this->tokens[$pId])) {
+            return $this->tokens[$pId];
+        } else {
+            throw new PHPExcel_Calculation_Exception("Token with id $pId does not exist.");
+        }
+    }
+
+    /**
+     * Get Token count
+     *
+     * @return string
+     */
+    public function getTokenCount()
+    {
+        return count($this->tokens);
+    }
+
+    /**
+     * Get Tokens
+     *
+     * @return PHPExcel_Calculation_FormulaToken[]
+     */
+    public function getTokens()
+    {
+        return $this->tokens;
+    }
+
+    /**
+     * Parse to tokens
+     */
+    private function parseToTokens()
+    {
+        // No attempt is made to verify formulas; assumes formulas are derived from Excel, where
+        // they can only exist if valid; stack overflows/underflows sunk as nulls without exceptions.
+
+        // Check if the formula has a valid starting =
+        $formulaLength = strlen($this->formula);
+        if ($formulaLength < 2 || $this->formula{0} != '=') {
+            return;
+        }
+
+        // Helper variables
+        $tokens1    = $tokens2     = $stack = array();
+        $inString    = $inPath     = $inRange     = $inError = false;
+        $token        = $previousToken    = $nextToken    = null;
+
+        $index    = 1;
+        $value    = '';
+
+        $ERRORS             = array("#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A");
+        $COMPARATORS_MULTI     = array(">=", "<=", "<>");
+
+        while ($index < $formulaLength) {
+            // state-dependent character evaluation (order is important)
+
+            // double-quoted strings
+            // embeds are doubled
+            // end marks token
+            if ($inString) {
+                if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) {
+                    if ((($index + 2) <= $formulaLength) && ($this->formula{$index + 1} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE)) {
+                        $value .= PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE;
+                        ++$index;
+                    } else {
+                        $inString = false;
+                        $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_TEXT);
+                        $value = "";
+                    }
+                } else {
+                    $value .= $this->formula{$index};
+                }
+                ++$index;
+                continue;
+            }
+
+            // single-quoted strings (links)
+            // embeds are double
+            // end does not mark a token
+            if ($inPath) {
+                if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) {
+                    if ((($index + 2) <= $formulaLength) && ($this->formula{$index + 1} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE)) {
+                        $value .= PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE;
+                        ++$index;
+                    } else {
+                        $inPath = false;
+                    }
+                } else {
+                    $value .= $this->formula{$index};
+                }
+                ++$index;
+                continue;
+            }
+
+            // bracked strings (R1C1 range index or linked workbook name)
+            // no embeds (changed to "()" by Excel)
+            // end does not mark a token
+            if ($inRange) {
+                if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACKET_CLOSE) {
+                    $inRange = false;
+                }
+                $value .= $this->formula{$index};
+                ++$index;
+                continue;
+            }
+
+            // error values
+            // end marks a token, determined from absolute list of values
+            if ($inError) {
+                $value .= $this->formula{$index};
+                ++$index;
+                if (in_array($value, $ERRORS)) {
+                    $inError = false;
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_ERROR);
+                    $value = "";
+                }
+                continue;
+            }
+
+            // scientific notation check
+            if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_SN, $this->formula{$index}) !== false) {
+                if (strlen($value) > 1) {
+                    if (preg_match("/^[1-9]{1}(\.[0-9]+)?E{1}$/", $this->formula{$index}) != 0) {
+                        $value .= $this->formula{$index};
+                        ++$index;
+                        continue;
+                    }
+                }
+            }
+
+            // independent character evaluation (order not important)
+
+            // establish state-dependent character evaluations
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) {
+                if (strlen($value > 0)) {
+                    // unexpected
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+                    $value = "";
+                }
+                $inString = true;
+                ++$index;
+                continue;
+            }
+
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) {
+                if (strlen($value) > 0) {
+                    // unexpected
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+                    $value = "";
+                }
+                $inPath = true;
+                ++$index;
+                continue;
+            }
+
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACKET_OPEN) {
+                $inRange = true;
+                $value .= PHPExcel_Calculation_FormulaParser::BRACKET_OPEN;
+                ++$index;
+                continue;
+            }
+
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::ERROR_START) {
+                if (strlen($value) > 0) {
+                    // unexpected
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+                    $value = "";
+                }
+                $inError = true;
+                $value .= PHPExcel_Calculation_FormulaParser::ERROR_START;
+                ++$index;
+                continue;
+            }
+
+            // mark start and end of arrays and array rows
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACE_OPEN) {
+                if (strlen($value) > 0) {
+                    // unexpected
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+                    $value = "";
+                }
+
+                $tmp = new PHPExcel_Calculation_FormulaToken("ARRAY", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+                $tokens1[] = $tmp;
+                $stack[] = clone $tmp;
+
+                $tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+                $tokens1[] = $tmp;
+                $stack[] = clone $tmp;
+
+                ++$index;
+                continue;
+            }
+
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::SEMICOLON) {
+                if (strlen($value) > 0) {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                    $value = "";
+                }
+
+                $tmp = array_pop($stack);
+                $tmp->setValue("");
+                $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+                $tokens1[] = $tmp;
+
+                $tmp = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT);
+                $tokens1[] = $tmp;
+
+                $tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+                $tokens1[] = $tmp;
+                $stack[] = clone $tmp;
+
+                ++$index;
+                continue;
+            }
+
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACE_CLOSE) {
+                if (strlen($value) > 0) {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                    $value = "";
+                }
+
+                $tmp = array_pop($stack);
+                $tmp->setValue("");
+                $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+                $tokens1[] = $tmp;
+
+                $tmp = array_pop($stack);
+                $tmp->setValue("");
+                $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+                $tokens1[] = $tmp;
+
+                ++$index;
+                continue;
+            }
+
+            // trim white-space
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::WHITESPACE) {
+                if (strlen($value) > 0) {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                    $value = "";
+                }
+                $tokens1[] = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE);
+                ++$index;
+                while (($this->formula{$index} == PHPExcel_Calculation_FormulaParser::WHITESPACE) && ($index < $formulaLength)) {
+                    ++$index;
+                }
+                continue;
+            }
+
+            // multi-character comparators
+            if (($index + 2) <= $formulaLength) {
+                if (in_array(substr($this->formula, $index, 2), $COMPARATORS_MULTI)) {
+                    if (strlen($value) > 0) {
+                        $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                        $value = "";
+                    }
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken(substr($this->formula, $index, 2), PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL);
+                    $index += 2;
+                    continue;
+                }
+            }
+
+            // standard infix operators
+            if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_INFIX, $this->formula{$index}) !== false) {
+                if (strlen($value) > 0) {
+                    $tokens1[] =new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                    $value = "";
+                }
+                $tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula{$index}, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX);
+                ++$index;
+                continue;
+            }
+
+            // standard postfix operators (only one)
+            if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_POSTFIX, $this->formula{$index}) !== false) {
+                if (strlen($value) > 0) {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                    $value = "";
+                }
+                $tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula{$index}, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX);
+                ++$index;
+                continue;
+            }
+
+            // start subexpression or function
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::PAREN_OPEN) {
+                if (strlen($value) > 0) {
+                    $tmp = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+                    $tokens1[] = $tmp;
+                    $stack[] = clone $tmp;
+                    $value = "";
+                } else {
+                    $tmp = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+                    $tokens1[] = $tmp;
+                    $stack[] = clone $tmp;
+                }
+                ++$index;
+                continue;
+            }
+
+            // function, subexpression, or array parameters, or operand unions
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::COMMA) {
+                if (strlen($value) > 0) {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                    $value = "";
+                }
+
+                $tmp = array_pop($stack);
+                $tmp->setValue("");
+                $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+                $stack[] = $tmp;
+
+                if ($tmp->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_UNION);
+                } else {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT);
+                }
+                ++$index;
+                continue;
+            }
+
+            // stop subexpression
+            if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::PAREN_CLOSE) {
+                if (strlen($value) > 0) {
+                    $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+                    $value = "";
+                }
+
+                $tmp = array_pop($stack);
+                $tmp->setValue("");
+                $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+                $tokens1[] = $tmp;
+
+                ++$index;
+                continue;
+            }
+
+            // token accumulation
+            $value .= $this->formula{$index};
+            ++$index;
+        }
+
+        // dump remaining accumulation
+        if (strlen($value) > 0) {
+            $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+        }
+
+        // move tokenList to new set, excluding unnecessary white-space tokens and converting necessary ones to intersections
+        $tokenCount = count($tokens1);
+        for ($i = 0; $i < $tokenCount; ++$i) {
+            $token = $tokens1[$i];
+            if (isset($tokens1[$i - 1])) {
+                $previousToken = $tokens1[$i - 1];
+            } else {
+                $previousToken = null;
+            }
+            if (isset($tokens1[$i + 1])) {
+                $nextToken = $tokens1[$i + 1];
+            } else {
+                $nextToken = null;
+            }
+
+            if (is_null($token)) {
+                continue;
+            }
+
+            if ($token->getTokenType() != PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE) {
+                $tokens2[] = $token;
+                continue;
+            }
+
+            if (is_null($previousToken)) {
+                continue;
+            }
+
+            if (! (
+                    (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+                    (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+                    ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)
+                  ) ) {
+                continue;
+            }
+
+            if (is_null($nextToken)) {
+                continue;
+            }
+
+            if (! (
+                    (($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) ||
+                    (($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) ||
+                    ($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)
+                  ) ) {
+                continue;
+            }
+
+            $tokens2[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_INTERSECTION);
+        }
+
+        // move tokens to final list, switching infix "-" operators to prefix when appropriate, switching infix "+" operators
+        // to noop when appropriate, identifying operand and infix-operator subtypes, and pulling "@" from function names
+        $this->tokens = array();
+
+        $tokenCount = count($tokens2);
+        for ($i = 0; $i < $tokenCount; ++$i) {
+            $token = $tokens2[$i];
+            if (isset($tokens2[$i - 1])) {
+                $previousToken = $tokens2[$i - 1];
+            } else {
+                $previousToken = null;
+            }
+            if (isset($tokens2[$i + 1])) {
+                $nextToken = $tokens2[$i + 1];
+            } else {
+                $nextToken = null;
+            }
+
+            if (is_null($token)) {
+                continue;
+            }
+
+            if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "-") {
+                if ($i == 0) {
+                    $token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX);
+                } elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) &&
+                    ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+                    (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) &&
+                    ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+                    ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) ||
+                    ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) {
+                    $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH);
+                } else {
+                    $token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX);
+                }
+
+                $this->tokens[] = $token;
+                continue;
+            }
+
+            if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "+") {
+                if ($i == 0) {
+                    continue;
+                } elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) &&
+                    ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+                    (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) &&
+                    ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+                    ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) ||
+                    ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) {
+                    $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH);
+                } else {
+                    continue;
+                }
+
+                $this->tokens[] = $token;
+                continue;
+            }
+
+            if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX &&
+                $token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) {
+                if (strpos("<>=", substr($token->getValue(), 0, 1)) !== false) {
+                    $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL);
+                } elseif ($token->getValue() == "&") {
+                    $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_CONCATENATION);
+                } else {
+                    $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH);
+                }
+
+                $this->tokens[] = $token;
+                continue;
+            }
+
+            if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND &&
+                $token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) {
+                if (!is_numeric($token->getValue())) {
+                    if (strtoupper($token->getValue()) == "TRUE" || strtoupper($token->getValue() == "FALSE")) {
+                        $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL);
+                    } else {
+                        $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_RANGE);
+                    }
+                } else {
+                    $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NUMBER);
+                }
+
+                $this->tokens[] = $token;
+                continue;
+            }
+
+            if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) {
+                if (strlen($token->getValue() > 0)) {
+                    if (substr($token->getValue(), 0, 1) == "@") {
+                        $token->setValue(substr($token->getValue(), 1));
+                    }
+                }
+            }
+
+            $this->tokens[] = $token;
+        }
+    }
+}

+ 176 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/FormulaToken.php

@@ -0,0 +1,176 @@
+<?php
+
+/*
+PARTLY BASED ON:
+    Copyright (c) 2007 E. W. Bachtal, Inc.
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+    and associated documentation files (the "Software"), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+      The above copyright notice and this permission notice shall be included in all copies or substantial
+      portions of the Software.
+
+    The software is provided "as is", without warranty of any kind, express or implied, including but not
+    limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In
+    no event shall the authors or copyright holders be liable for any claim, damages or other liability,
+    whether in an action of contract, tort or otherwise, arising from, out of or in connection with the
+    software or the use or other dealings in the software.
+
+    http://ewbi.blogs.com/develops/2007/03/excel_formula_p.html
+    http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html
+*/
+
+/**
+ * PHPExcel_Calculation_FormulaToken
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+
+
+class PHPExcel_Calculation_FormulaToken
+{
+    /* Token types */
+    const TOKEN_TYPE_NOOP            = 'Noop';
+    const TOKEN_TYPE_OPERAND         = 'Operand';
+    const TOKEN_TYPE_FUNCTION        = 'Function';
+    const TOKEN_TYPE_SUBEXPRESSION   = 'Subexpression';
+    const TOKEN_TYPE_ARGUMENT        = 'Argument';
+    const TOKEN_TYPE_OPERATORPREFIX  = 'OperatorPrefix';
+    const TOKEN_TYPE_OPERATORINFIX   = 'OperatorInfix';
+    const TOKEN_TYPE_OPERATORPOSTFIX = 'OperatorPostfix';
+    const TOKEN_TYPE_WHITESPACE      = 'Whitespace';
+    const TOKEN_TYPE_UNKNOWN         = 'Unknown';
+
+    /* Token subtypes */
+    const TOKEN_SUBTYPE_NOTHING       = 'Nothing';
+    const TOKEN_SUBTYPE_START         = 'Start';
+    const TOKEN_SUBTYPE_STOP          = 'Stop';
+    const TOKEN_SUBTYPE_TEXT          = 'Text';
+    const TOKEN_SUBTYPE_NUMBER        = 'Number';
+    const TOKEN_SUBTYPE_LOGICAL       = 'Logical';
+    const TOKEN_SUBTYPE_ERROR         = 'Error';
+    const TOKEN_SUBTYPE_RANGE         = 'Range';
+    const TOKEN_SUBTYPE_MATH          = 'Math';
+    const TOKEN_SUBTYPE_CONCATENATION = 'Concatenation';
+    const TOKEN_SUBTYPE_INTERSECTION  = 'Intersection';
+    const TOKEN_SUBTYPE_UNION         = 'Union';
+
+    /**
+     * Value
+     *
+     * @var string
+     */
+    private $value;
+
+    /**
+     * Token Type (represented by TOKEN_TYPE_*)
+     *
+     * @var string
+     */
+    private $tokenType;
+
+    /**
+     * Token SubType (represented by TOKEN_SUBTYPE_*)
+     *
+     * @var string
+     */
+    private $tokenSubType;
+
+    /**
+     * Create a new PHPExcel_Calculation_FormulaToken
+     *
+     * @param string    $pValue
+     * @param string    $pTokenType     Token type (represented by TOKEN_TYPE_*)
+     * @param string    $pTokenSubType     Token Subtype (represented by TOKEN_SUBTYPE_*)
+     */
+    public function __construct($pValue, $pTokenType = PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN, $pTokenSubType = PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING)
+    {
+        // Initialise values
+        $this->value       = $pValue;
+        $this->tokenType    = $pTokenType;
+        $this->tokenSubType = $pTokenSubType;
+    }
+
+    /**
+     * Get Value
+     *
+     * @return string
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * Set Value
+     *
+     * @param string    $value
+     */
+    public function setValue($value)
+    {
+        $this->value = $value;
+    }
+
+    /**
+     * Get Token Type (represented by TOKEN_TYPE_*)
+     *
+     * @return string
+     */
+    public function getTokenType()
+    {
+        return $this->tokenType;
+    }
+
+    /**
+     * Set Token Type
+     *
+     * @param string    $value
+     */
+    public function setTokenType($value = PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN)
+    {
+        $this->tokenType = $value;
+    }
+
+    /**
+     * Get Token SubType (represented by TOKEN_SUBTYPE_*)
+     *
+     * @return string
+     */
+    public function getTokenSubType()
+    {
+        return $this->tokenSubType;
+    }
+
+    /**
+     * Set Token SubType
+     *
+     * @param string    $value
+     */
+    public function setTokenSubType($value = PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING)
+    {
+        $this->tokenSubType = $value;
+    }
+}

+ 148 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Function.php

@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * PHPExcel_Calculation_Function
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_Function
+{
+    /* Function categories */
+    const CATEGORY_CUBE                 = 'Cube';
+    const CATEGORY_DATABASE             = 'Database';
+    const CATEGORY_DATE_AND_TIME        = 'Date and Time';
+    const CATEGORY_ENGINEERING          = 'Engineering';
+    const CATEGORY_FINANCIAL            = 'Financial';
+    const CATEGORY_INFORMATION          = 'Information';
+    const CATEGORY_LOGICAL              = 'Logical';
+    const CATEGORY_LOOKUP_AND_REFERENCE = 'Lookup and Reference';
+    const CATEGORY_MATH_AND_TRIG        = 'Math and Trig';
+    const CATEGORY_STATISTICAL          = 'Statistical';
+    const CATEGORY_TEXT_AND_DATA        = 'Text and Data';
+
+    /**
+     * Category (represented by CATEGORY_*)
+     *
+     * @var string
+     */
+    private $category;
+
+    /**
+     * Excel name
+     *
+     * @var string
+     */
+    private $excelName;
+
+    /**
+     * PHPExcel name
+     *
+     * @var string
+     */
+    private $phpExcelName;
+
+    /**
+     * Create a new PHPExcel_Calculation_Function
+     *
+     * @param     string        $pCategory         Category (represented by CATEGORY_*)
+     * @param     string        $pExcelName        Excel function name
+     * @param     string        $pPHPExcelName    PHPExcel function mapping
+     * @throws     PHPExcel_Calculation_Exception
+     */
+    public function __construct($pCategory = null, $pExcelName = null, $pPHPExcelName = null)
+    {
+        if (($pCategory !== null) && ($pExcelName !== null) && ($pPHPExcelName !== null)) {
+            // Initialise values
+            $this->category     = $pCategory;
+            $this->excelName    = $pExcelName;
+            $this->phpExcelName = $pPHPExcelName;
+        } else {
+            throw new PHPExcel_Calculation_Exception("Invalid parameters passed.");
+        }
+    }
+
+    /**
+     * Get Category (represented by CATEGORY_*)
+     *
+     * @return string
+     */
+    public function getCategory()
+    {
+        return $this->category;
+    }
+
+    /**
+     * Set Category (represented by CATEGORY_*)
+     *
+     * @param     string        $value
+     * @throws     PHPExcel_Calculation_Exception
+     */
+    public function setCategory($value = null)
+    {
+        if (!is_null($value)) {
+            $this->category = $value;
+        } else {
+            throw new PHPExcel_Calculation_Exception("Invalid parameter passed.");
+        }
+    }
+
+    /**
+     * Get Excel name
+     *
+     * @return string
+     */
+    public function getExcelName()
+    {
+        return $this->excelName;
+    }
+
+    /**
+     * Set Excel name
+     *
+     * @param string    $value
+     */
+    public function setExcelName($value)
+    {
+        $this->excelName = $value;
+    }
+
+    /**
+     * Get PHPExcel name
+     *
+     * @return string
+     */
+    public function getPHPExcelName()
+    {
+        return $this->phpExcelName;
+    }
+
+    /**
+     * Set PHPExcel name
+     *
+     * @param string    $value
+     */
+    public function setPHPExcelName($value)
+    {
+        $this->phpExcelName = $value;
+    }
+}

+ 760 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Functions.php

@@ -0,0 +1,760 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+
+/** MAX_VALUE */
+define('MAX_VALUE', 1.2e308);
+
+/** 2 / PI */
+define('M_2DIVPI', 0.63661977236758134307553505349006);
+
+/** MAX_ITERATIONS */
+define('MAX_ITERATIONS', 256);
+
+/** PRECISION */
+define('PRECISION', 8.88E-016);
+
+
+/**
+ * PHPExcel_Calculation_Functions
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_Functions
+{
+
+    /** constants */
+    const COMPATIBILITY_EXCEL      = 'Excel';
+    const COMPATIBILITY_GNUMERIC   = 'Gnumeric';
+    const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc';
+
+    const RETURNDATE_PHP_NUMERIC = 'P';
+    const RETURNDATE_PHP_OBJECT  = 'O';
+    const RETURNDATE_EXCEL       = 'E';
+
+
+    /**
+     * Compatibility mode to use for error checking and responses
+     *
+     * @access    private
+     * @var string
+     */
+    protected static $compatibilityMode = self::COMPATIBILITY_EXCEL;
+
+    /**
+     * Data Type to use when returning date values
+     *
+     * @access    private
+     * @var string
+     */
+    protected static $returnDateType = self::RETURNDATE_EXCEL;
+
+    /**
+     * List of error codes
+     *
+     * @access    private
+     * @var array
+     */
+    protected static $errorCodes = array(
+        'null'           => '#NULL!',
+        'divisionbyzero' => '#DIV/0!',
+        'value'          => '#VALUE!',
+        'reference'      => '#REF!',
+        'name'           => '#NAME?',
+        'num'            => '#NUM!',
+        'na'             => '#N/A',
+        'gettingdata'    => '#GETTING_DATA'
+    );
+
+
+    /**
+     * Set the Compatibility Mode
+     *
+     * @access    public
+     * @category Function Configuration
+     * @param     string        $compatibilityMode        Compatibility Mode
+     *                                                Permitted values are:
+     *                                                    PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
+     *                                                    PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
+     *                                                    PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
+     * @return     boolean    (Success or Failure)
+     */
+    public static function setCompatibilityMode($compatibilityMode)
+    {
+        if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
+            ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
+            ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
+            self::$compatibilityMode = $compatibilityMode;
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Return the current Compatibility Mode
+     *
+     * @access    public
+     * @category Function Configuration
+     * @return     string        Compatibility Mode
+     *                            Possible Return values are:
+     *                                PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL            'Excel'
+     *                                PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC        'Gnumeric'
+     *                                PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE    'OpenOfficeCalc'
+     */
+    public static function getCompatibilityMode()
+    {
+        return self::$compatibilityMode;
+    }
+
+
+    /**
+     * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
+     *
+     * @access    public
+     * @category Function Configuration
+     * @param     string    $returnDateType            Return Date Format
+     *                                                Permitted values are:
+     *                                                    PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
+     *                                                    PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
+     *                                                    PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
+     * @return     boolean                            Success or failure
+     */
+    public static function setReturnDateType($returnDateType)
+    {
+        if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
+            ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
+            ($returnDateType == self::RETURNDATE_EXCEL)) {
+            self::$returnDateType = $returnDateType;
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
+     *
+     * @access    public
+     * @category Function Configuration
+     * @return     string        Return Date Format
+     *                            Possible Return values are:
+     *                                PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC        'P'
+     *                                PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT        'O'
+     *                                PHPExcel_Calculation_Functions::RETURNDATE_EXCEL            'E'
+     */
+    public static function getReturnDateType()
+    {
+        return self::$returnDateType;
+    }
+
+
+    /**
+     * DUMMY
+     *
+     * @access    public
+     * @category Error Returns
+     * @return    string    #Not Yet Implemented
+     */
+    public static function DUMMY()
+    {
+        return '#Not Yet Implemented';
+    }
+
+
+    /**
+     * DIV0
+     *
+     * @access    public
+     * @category Error Returns
+     * @return    string    #Not Yet Implemented
+     */
+    public static function DIV0()
+    {
+        return self::$errorCodes['divisionbyzero'];
+    }
+
+
+    /**
+     * NA
+     *
+     * Excel Function:
+     *        =NA()
+     *
+     * Returns the error value #N/A
+     *        #N/A is the error value that means "no value is available."
+     *
+     * @access    public
+     * @category Logical Functions
+     * @return    string    #N/A!
+     */
+    public static function NA()
+    {
+        return self::$errorCodes['na'];
+    }
+
+
+    /**
+     * NaN
+     *
+     * Returns the error value #NUM!
+     *
+     * @access    public
+     * @category Error Returns
+     * @return    string    #NUM!
+     */
+    public static function NaN()
+    {
+        return self::$errorCodes['num'];
+    }
+
+
+    /**
+     * NAME
+     *
+     * Returns the error value #NAME?
+     *
+     * @access    public
+     * @category Error Returns
+     * @return    string    #NAME?
+     */
+    public static function NAME()
+    {
+        return self::$errorCodes['name'];
+    }
+
+
+    /**
+     * REF
+     *
+     * Returns the error value #REF!
+     *
+     * @access    public
+     * @category Error Returns
+     * @return    string    #REF!
+     */
+    public static function REF()
+    {
+        return self::$errorCodes['reference'];
+    }
+
+
+    /**
+     * NULL
+     *
+     * Returns the error value #NULL!
+     *
+     * @access    public
+     * @category Error Returns
+     * @return    string    #NULL!
+     */
+    public static function NULL()
+    {
+        return self::$errorCodes['null'];
+    }
+
+
+    /**
+     * VALUE
+     *
+     * Returns the error value #VALUE!
+     *
+     * @access    public
+     * @category Error Returns
+     * @return    string    #VALUE!
+     */
+    public static function VALUE()
+    {
+        return self::$errorCodes['value'];
+    }
+
+
+    public static function isMatrixValue($idx)
+    {
+        return ((substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0));
+    }
+
+
+    public static function isValue($idx)
+    {
+        return (substr_count($idx, '.') == 0);
+    }
+
+
+    public static function isCellValue($idx)
+    {
+        return (substr_count($idx, '.') > 1);
+    }
+
+
+    public static function ifCondition($condition)
+    {
+        $condition    = PHPExcel_Calculation_Functions::flattenSingleValue($condition);
+        if (!isset($condition{0})) {
+            $condition = '=""';
+        }
+        if (!in_array($condition{0}, array('>', '<', '='))) {
+            if (!is_numeric($condition)) {
+                $condition = PHPExcel_Calculation::wrapResult(strtoupper($condition));
+            }
+            return '=' . $condition;
+        } else {
+            preg_match('/([<>=]+)(.*)/', $condition, $matches);
+            list(, $operator, $operand) = $matches;
+
+            if (!is_numeric($operand)) {
+                $operand = str_replace('"', '""', $operand);
+                $operand = PHPExcel_Calculation::wrapResult(strtoupper($operand));
+            }
+
+            return $operator.$operand;
+        }
+    }
+
+    /**
+     * ERROR_TYPE
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function ERROR_TYPE($value = '')
+    {
+        $value = self::flattenSingleValue($value);
+
+        $i = 1;
+        foreach (self::$errorCodes as $errorCode) {
+            if ($value === $errorCode) {
+                return $i;
+            }
+            ++$i;
+        }
+        return self::NA();
+    }
+
+
+    /**
+     * IS_BLANK
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function IS_BLANK($value = null)
+    {
+        if (!is_null($value)) {
+            $value    = self::flattenSingleValue($value);
+        }
+
+        return is_null($value);
+    }
+
+
+    /**
+     * IS_ERR
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function IS_ERR($value = '')
+    {
+        $value = self::flattenSingleValue($value);
+
+        return self::IS_ERROR($value) && (!self::IS_NA($value));
+    }
+
+
+    /**
+     * IS_ERROR
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function IS_ERROR($value = '')
+    {
+        $value = self::flattenSingleValue($value);
+
+        if (!is_string($value)) {
+            return false;
+        }
+        return in_array($value, array_values(self::$errorCodes));
+    }
+
+
+    /**
+     * IS_NA
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function IS_NA($value = '')
+    {
+        $value = self::flattenSingleValue($value);
+
+        return ($value === self::NA());
+    }
+
+
+    /**
+     * IS_EVEN
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function IS_EVEN($value = null)
+    {
+        $value = self::flattenSingleValue($value);
+
+        if ($value === null) {
+            return self::NAME();
+        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
+            return self::VALUE();
+        }
+
+        return ($value % 2 == 0);
+    }
+
+
+    /**
+     * IS_ODD
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function IS_ODD($value = null)
+    {
+        $value = self::flattenSingleValue($value);
+
+        if ($value === null) {
+            return self::NAME();
+        } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
+            return self::VALUE();
+        }
+
+        return (abs($value) % 2 == 1);
+    }
+
+
+    /**
+     * IS_NUMBER
+     *
+     * @param    mixed    $value        Value to check
+     * @return    boolean
+     */
+    public static function IS_NUMBER($value = null)
+    {
+        $value = self::flattenSingleValue($value);
+
+        if (is_string($value)) {
+            return false;
+        }
+        return is_numeric($value);
+    }
+
+
+    /**
+     * IS_LOGICAL
+     *
+     * @param    mixed    $value        Value to check
+     * @return    boolean
+     */
+    public static function IS_LOGICAL($value = null)
+    {
+        $value = self::flattenSingleValue($value);
+
+        return is_bool($value);
+    }
+
+
+    /**
+     * IS_TEXT
+     *
+     * @param    mixed    $value        Value to check
+     * @return    boolean
+     */
+    public static function IS_TEXT($value = null)
+    {
+        $value = self::flattenSingleValue($value);
+
+        return (is_string($value) && !self::IS_ERROR($value));
+    }
+
+
+    /**
+     * IS_NONTEXT
+     *
+     * @param    mixed    $value        Value to check
+     * @return    boolean
+     */
+    public static function IS_NONTEXT($value = null)
+    {
+        return !self::IS_TEXT($value);
+    }
+
+
+    /**
+     * VERSION
+     *
+     * @return    string    Version information
+     */
+    public static function VERSION()
+    {
+        return 'PHPExcel ##VERSION##, ##DATE##';
+    }
+
+
+    /**
+     * N
+     *
+     * Returns a value converted to a number
+     *
+     * @param    value        The value you want converted
+     * @return    number        N converts values listed in the following table
+     *        If value is or refers to N returns
+     *        A number            That number
+     *        A date                The serial number of that date
+     *        TRUE                1
+     *        FALSE                0
+     *        An error value        The error value
+     *        Anything else        0
+     */
+    public static function N($value = null)
+    {
+        while (is_array($value)) {
+            $value = array_shift($value);
+        }
+
+        switch (gettype($value)) {
+            case 'double':
+            case 'float':
+            case 'integer':
+                return $value;
+            case 'boolean':
+                return (integer) $value;
+            case 'string':
+                //    Errors
+                if ((strlen($value) > 0) && ($value{0} == '#')) {
+                    return $value;
+                }
+                break;
+        }
+        return 0;
+    }
+
+
+    /**
+     * TYPE
+     *
+     * Returns a number that identifies the type of a value
+     *
+     * @param    value        The value you want tested
+     * @return    number        N converts values listed in the following table
+     *        If value is or refers to N returns
+     *        A number            1
+     *        Text                2
+     *        Logical Value        4
+     *        An error value        16
+     *        Array or Matrix        64
+     */
+    public static function TYPE($value = null)
+    {
+        $value = self::flattenArrayIndexed($value);
+        if (is_array($value) && (count($value) > 1)) {
+            end($value);
+            $a = key($value);
+            //    Range of cells is an error
+            if (self::isCellValue($a)) {
+                return 16;
+            //    Test for Matrix
+            } elseif (self::isMatrixValue($a)) {
+                return 64;
+            }
+        } elseif (empty($value)) {
+            //    Empty Cell
+            return 1;
+        }
+        $value = self::flattenSingleValue($value);
+
+        if (($value === null) || (is_float($value)) || (is_int($value))) {
+                return 1;
+        } elseif (is_bool($value)) {
+                return 4;
+        } elseif (is_array($value)) {
+                return 64;
+        } elseif (is_string($value)) {
+            //    Errors
+            if ((strlen($value) > 0) && ($value{0} == '#')) {
+                return 16;
+            }
+            return 2;
+        }
+        return 0;
+    }
+
+
+    /**
+     * Convert a multi-dimensional array to a simple 1-dimensional array
+     *
+     * @param    array    $array    Array to be flattened
+     * @return    array    Flattened array
+     */
+    public static function flattenArray($array)
+    {
+        if (!is_array($array)) {
+            return (array) $array;
+        }
+
+        $arrayValues = array();
+        foreach ($array as $value) {
+            if (is_array($value)) {
+                foreach ($value as $val) {
+                    if (is_array($val)) {
+                        foreach ($val as $v) {
+                            $arrayValues[] = $v;
+                        }
+                    } else {
+                        $arrayValues[] = $val;
+                    }
+                }
+            } else {
+                $arrayValues[] = $value;
+            }
+        }
+
+        return $arrayValues;
+    }
+
+
+    /**
+     * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
+     *
+     * @param    array    $array    Array to be flattened
+     * @return    array    Flattened array
+     */
+    public static function flattenArrayIndexed($array)
+    {
+        if (!is_array($array)) {
+            return (array) $array;
+        }
+
+        $arrayValues = array();
+        foreach ($array as $k1 => $value) {
+            if (is_array($value)) {
+                foreach ($value as $k2 => $val) {
+                    if (is_array($val)) {
+                        foreach ($val as $k3 => $v) {
+                            $arrayValues[$k1.'.'.$k2.'.'.$k3] = $v;
+                        }
+                    } else {
+                        $arrayValues[$k1.'.'.$k2] = $val;
+                    }
+                }
+            } else {
+                $arrayValues[$k1] = $value;
+            }
+        }
+
+        return $arrayValues;
+    }
+
+
+    /**
+     * Convert an array to a single scalar value by extracting the first element
+     *
+     * @param    mixed        $value        Array or scalar value
+     * @return    mixed
+     */
+    public static function flattenSingleValue($value = '')
+    {
+        while (is_array($value)) {
+            $value = array_pop($value);
+        }
+
+        return $value;
+    }
+}
+
+
+//
+//    There are a few mathematical functions that aren't available on all versions of PHP for all platforms
+//    These functions aren't available in Windows implementations of PHP prior to version 5.3.0
+//    So we test if they do exist for this version of PHP/operating platform; and if not we create them
+//
+if (!function_exists('acosh')) {
+    function acosh($x)
+    {
+        return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2));
+    }    //    function acosh()
+}
+
+if (!function_exists('asinh')) {
+    function asinh($x)
+    {
+        return log($x + sqrt(1 + $x * $x));
+    }    //    function asinh()
+}
+
+if (!function_exists('atanh')) {
+    function atanh($x)
+    {
+        return (log(1 + $x) - log(1 - $x)) / 2;
+    }    //    function atanh()
+}
+
+
+//
+//    Strangely, PHP doesn't have a mb_str_replace multibyte function
+//    As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
+//
+if ((!function_exists('mb_str_replace')) &&
+    (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) {
+    function mb_str_replace($search, $replace, $subject)
+    {
+        if (is_array($subject)) {
+            $ret = array();
+            foreach ($subject as $key => $val) {
+                $ret[$key] = mb_str_replace($search, $replace, $val);
+            }
+            return $ret;
+        }
+
+        foreach ((array) $search as $key => $s) {
+            if ($s == '' && $s !== 0) {
+                continue;
+            }
+            $r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : '');
+            $pos = mb_strpos($subject, $s, 0, 'UTF-8');
+            while ($pos !== false) {
+                $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8');
+                $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8');
+            }
+        }
+        return $subject;
+    }
+}

+ 285 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Logical.php

@@ -0,0 +1,285 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Calculation_Logical
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_Logical
+{
+    /**
+     * TRUE
+     *
+     * Returns the boolean TRUE.
+     *
+     * Excel Function:
+     *        =TRUE()
+     *
+     * @access    public
+     * @category Logical Functions
+     * @return    boolean        True
+     */
+    public static function TRUE()
+    {
+        return true;
+    }
+
+
+    /**
+     * FALSE
+     *
+     * Returns the boolean FALSE.
+     *
+     * Excel Function:
+     *        =FALSE()
+     *
+     * @access    public
+     * @category Logical Functions
+     * @return    boolean        False
+     */
+    public static function FALSE()
+    {
+        return false;
+    }
+
+
+    /**
+     * 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 = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+        $argCount = -1;
+        foreach ($aArgs as $argCount => $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 == PHPExcel_Calculation::getTRUE())) {
+                    $arg = true;
+                } elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) {
+                    $arg = false;
+                } else {
+                    return PHPExcel_Calculation_Functions::VALUE();
+                }
+                $returnValue = $returnValue && ($arg != 0);
+            }
+        }
+
+        // Return
+        if ($argCount < 0) {
+            return PHPExcel_Calculation_Functions::VALUE();
+        }
+        return $returnValue;
+    }
+
+
+    /**
+     * 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 = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+        $argCount = -1;
+        foreach ($aArgs as $argCount => $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 == PHPExcel_Calculation::getTRUE())) {
+                    $arg = true;
+                } elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) {
+                    $arg = false;
+                } else {
+                    return PHPExcel_Calculation_Functions::VALUE();
+                }
+                $returnValue = $returnValue || ($arg != 0);
+            }
+        }
+
+        // Return
+        if ($argCount < 0) {
+            return PHPExcel_Calculation_Functions::VALUE();
+        }
+        return $returnValue;
+    }
+
+
+    /**
+     * 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 NOT($logical = false)
+    {
+        $logical = PHPExcel_Calculation_Functions::flattenSingleValue($logical);
+        if (is_string($logical)) {
+            $logical = strtoupper($logical);
+            if (($logical == 'TRUE') || ($logical == PHPExcel_Calculation::getTRUE())) {
+                return false;
+            } elseif (($logical == 'FALSE') || ($logical == PHPExcel_Calculation::getFALSE())) {
+                return true;
+            } else {
+                return PHPExcel_Calculation_Functions::VALUE();
+            }
+        }
+
+        return !$logical;
+    }
+
+    /**
+     * 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) PHPExcel_Calculation_Functions::flattenSingleValue($condition);
+        $returnIfTrue  = (is_null($returnIfTrue))  ? 0 :     PHPExcel_Calculation_Functions::flattenSingleValue($returnIfTrue);
+        $returnIfFalse = (is_null($returnIfFalse)) ? false : PHPExcel_Calculation_Functions::flattenSingleValue($returnIfFalse);
+
+        return ($condition) ? $returnIfTrue : $returnIfFalse;
+    }
+
+
+    /**
+     * 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 IFERROR($testValue = '', $errorpart = '')
+    {
+        $testValue = (is_null($testValue)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($testValue);
+        $errorpart = (is_null($errorpart)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($errorpart);
+
+        return self::STATEMENT_IF(PHPExcel_Calculation_Functions::IS_ERROR($testValue), $errorpart, $testValue);
+    }
+}

+ 879 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/LookupRef.php

@@ -0,0 +1,879 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Calculation_LookupRef
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_LookupRef
+{
+    /**
+     * CELL_ADDRESS
+     *
+     * Creates a cell address as text, given specified row and column numbers.
+     *
+     * Excel Function:
+     *        =ADDRESS(row, column, [relativity], [referenceStyle], [sheetText])
+     *
+     * @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        = PHPExcel_Calculation_Functions::flattenSingleValue($row);
+        $column     = PHPExcel_Calculation_Functions::flattenSingleValue($column);
+        $relativity = PHPExcel_Calculation_Functions::flattenSingleValue($relativity);
+        $sheetText  = PHPExcel_Calculation_Functions::flattenSingleValue($sheetText);
+
+        if (($row < 1) || ($column < 1)) {
+            return PHPExcel_Calculation_Functions::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;
+        }
+    }
+
+
+    /**
+     * 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.
+     *
+     * Excel Function:
+     *        =COLUMN([cellAddress])
+     *
+     * @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);
+            }
+        }
+    }
+
+
+    /**
+     * COLUMNS
+     *
+     * Returns the number of columns in an array or reference.
+     *
+     * Excel Function:
+     *        =COLUMNS(cellAddress)
+     *
+     * @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            The number of columns in cellAddress
+     */
+    public static function COLUMNS($cellAddress = null)
+    {
+        if (is_null($cellAddress) || $cellAddress === '') {
+            return 1;
+        } elseif (!is_array($cellAddress)) {
+            return PHPExcel_Calculation_Functions::VALUE();
+        }
+
+        reset($cellAddress);
+        $isMatrix = (is_numeric(key($cellAddress)));
+        list($columns, $rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress);
+
+        if ($isMatrix) {
+            return $rows;
+        } else {
+            return $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.
+     *
+     * Excel Function:
+     *        =ROW([cellAddress])
+     *
+     * @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);
+            }
+        }
+    }
+
+
+    /**
+     * ROWS
+     *
+     * Returns the number of rows in an array or reference.
+     *
+     * Excel Function:
+     *        =ROWS(cellAddress)
+     *
+     * @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            The number of rows in cellAddress
+     */
+    public static function ROWS($cellAddress = null)
+    {
+        if (is_null($cellAddress) || $cellAddress === '') {
+            return 1;
+        } elseif (!is_array($cellAddress)) {
+            return PHPExcel_Calculation_Functions::VALUE();
+        }
+
+        reset($cellAddress);
+        $isMatrix = (is_numeric(key($cellAddress)));
+        list($columns, $rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress);
+
+        if ($isMatrix) {
+            return $columns;
+        } else {
+            return $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
+     * @param    PHPExcel_Cell    $pCell            The cell to set the hyperlink in
+     * @return    mixed    The value of $displayName (or $linkURL if $displayName was blank)
+     */
+    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);
+        $pCell->getHyperlink()->setTooltip($displayName);
+
+        return $displayName;
+    }
+
+
+    /**
+     * INDIRECT
+     *
+     * Returns the reference specified by a text string.
+     * References are immediately evaluated to display their contents.
+     *
+     * Excel Function:
+     *        =INDIRECT(cellAddress)
+     *
+     * NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010
+     *
+     * @param    cellAddress        $cellAddress    The cell address of the current cell (containing this formula)
+     * @param    PHPExcel_Cell    $pCell            The current cell (containing this formula)
+     * @return    mixed            The cells referenced by cellAddress
+     *
+     * @todo    Support for the optional a1 parameter introduced in Excel 2010
+     *
+     */
+    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)))) {
+            if (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $cellAddress1, $matches)) {
+                return PHPExcel_Calculation_Functions::REF();
+            }
+
+            if (strpos($cellAddress, '!') !== false) {
+                list($sheetName, $cellAddress) = explode('!', $cellAddress);
+                $sheetName = trim($sheetName, "'");
+                $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
+            } else {
+                $pSheet = $pCell->getWorksheet();
+            }
+
+            return PHPExcel_Calculation::getInstance()->extractNamedRange($cellAddress, $pSheet, false);
+        }
+
+        if (strpos($cellAddress, '!') !== false) {
+            list($sheetName, $cellAddress) = explode('!', $cellAddress);
+            $sheetName = trim($sheetName, "'");
+            $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
+        } else {
+            $pSheet = $pCell->getWorksheet();
+        }
+
+        return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false);
+    }
+
+
+    /**
+     * 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.
+     *
+     * Excel Function:
+     *        =OFFSET(cellAddress, rows, cols, [height], [width])
+     *
+     * @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);
+            $sheetName = trim($sheetName, "'");
+        }
+        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->getWorksheet()->getParent()->getSheetByName($sheetName);
+        } else {
+            $pSheet = $pCell->getWorksheet();
+        }
+
+        return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false);
+    }
+
+
+    /**
+     * CHOOSE
+     *
+     * Uses lookup_value to return a value from the list of value arguments.
+     * Use CHOOSE to select one of up to 254 values based on the lookup_value.
+     *
+     * Excel Function:
+     *        =CHOOSE(index_num, value1, [value2], ...)
+     *
+     * @param    index_num        Specifies which value argument is selected.
+     *                            Index_num must be a number between 1 and 254, or a formula or reference to a cell containing a number
+     *                                between 1 and 254.
+     * @param    value1...        Value1 is required, subsequent values are optional.
+     *                            Between 1 to 254 value arguments from which CHOOSE selects a value or an action to perform based on
+     *                                index_num. The arguments can be numbers, cell references, defined names, formulas, functions, or
+     *                                text.
+     * @return    mixed            The selected value
+     */
+    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];
+        }
+    }
+
+
+    /**
+     * MATCH
+     *
+     * The MATCH function searches for a specified item in a range of cells
+     *
+     * Excel Function:
+     *        =MATCH(lookup_value, lookup_array, [match_type])
+     *
+     * @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
+        // **
+        foreach ($lookup_array as $i => $lookupArrayValue) {
+            if (($match_type == 0) && ($lookupArrayValue == $lookup_value)) {
+                //    exact match
+                return ++$i;
+            } elseif (($match_type == -1) && ($lookupArrayValue <= $lookup_value)) {
+                $i = array_search($i, $keySet);
+                // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value
+                if ($i < 1) {
+                    // 1st cell was already 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)) {
+                $i = array_search($i, $keySet);
+                // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value
+                if ($i < 1) {
+                    // 1st cell was already 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();
+    }
+
+
+    /**
+     * INDEX
+     *
+     * Uses an index to choose a value from a reference or array
+     *
+     * Excel Function:
+     *        =INDEX(range_array, row_num, [column_num])
+     *
+     * @param    range_array        A range of cells or an array constant
+     * @param    row_num            The row in array from which to return a value. If row_num is omitted, column_num is required.
+     * @param    column_num        The column in array from which to return a value. If column_num is omitted, row_num is required.
+     * @return    mixed            the value of a specified cell or array of cells
+     */
+    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];
+    }
+
+
+    /**
+     * 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;
+    }
+
+
+    private static function vlookupSort($a, $b)
+    {
+        reset($a);
+        $firstColumn = key($a);
+        if (($aLower = strtolower($a[$firstColumn])) == ($bLower = strtolower($b[$firstColumn]))) {
+            return 0;
+        }
+        return ($aLower < $bLower) ? -1 : 1;
+    }
+
+
+    /**
+     * 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)) || (empty($lookup_array))) {
+            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 ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) ||
+                (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && (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();
+    }
+
+
+    /**
+     * HLOOKUP
+     * The HLOOKUP function searches for value in the top-most row of lookup_array and returns the value in the same column 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 row number in table_array from which the matching value must be returned. The first row 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 HLOOKUP($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)) || (empty($lookup_array))) {
+            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]);
+                                $firstkey = $f[0] - 1;
+                $returnColumn = $firstkey + $index_number;
+                $firstColumn = array_shift($f);
+            }
+        }
+
+        if (!$not_exact_match) {
+            $firstRowH = asort($lookup_array[$firstColumn]);
+        }
+
+        $rowNumber = $rowValue = false;
+        foreach ($lookup_array[$firstColumn] as $rowKey => $rowData) {
+            if ((is_numeric($lookup_value) && is_numeric($rowData) && ($rowData > $lookup_value)) ||
+                (!is_numeric($lookup_value) && !is_numeric($rowData) && (strtolower($rowData) > strtolower($lookup_value)))) {
+                break;
+            }
+            $rowNumber = $rowKey;
+            $rowValue = $rowData;
+        }
+
+        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[$returnColumn][$rowNumber];
+            }
+        }
+
+        return PHPExcel_Calculation_Functions::NA();
+    }
+
+
+    /**
+     * 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);
+    }
+}

File diff suppressed because it is too large
+ 1459 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/MathTrig.php


File diff suppressed because it is too large
+ 3745 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Statistical.php


+ 651 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/TextData.php

@@ -0,0 +1,651 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Calculation_TextData
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_TextData
+{
+    private static $invalidChars;
+
+    private static function unicodeToOrd($c)
+    {
+        if (ord($c{0}) >=0 && ord($c{0}) <= 127) {
+            return ord($c{0});
+        } elseif (ord($c{0}) >= 192 && ord($c{0}) <= 223) {
+            return (ord($c{0})-192)*64 + (ord($c{1})-128);
+        } elseif (ord($c{0}) >= 224 && ord($c{0}) <= 239) {
+            return (ord($c{0})-224)*4096 + (ord($c{1})-128)*64 + (ord($c{2})-128);
+        } elseif (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);
+        } elseif (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);
+        } elseif (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);
+        } elseif (ord($c{0}) >= 254 && ord($c{0}) <= 255) {
+            // error
+            return PHPExcel_Calculation_Functions::VALUE();
+        }
+        return 0;
+    }
+
+    /**
+     * 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    $stringValue    Value to check
+     * @return    string
+     */
+    public static function TRIMNONPRINTABLE($stringValue = '')
+    {
+        $stringValue    = PHPExcel_Calculation_Functions::flattenSingleValue($stringValue);
+
+        if (is_bool($stringValue)) {
+            return ($stringValue) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        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;
+    }
+
+
+    /**
+     * TRIMSPACES
+     *
+     * @param    mixed    $stringValue    Value to check
+     * @return    string
+     */
+    public static function TRIMSPACES($stringValue = '')
+    {
+        $stringValue = PHPExcel_Calculation_Functions::flattenSingleValue($stringValue);
+        if (is_bool($stringValue)) {
+            return ($stringValue) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        if (is_string($stringValue) || is_numeric($stringValue)) {
+            return trim(preg_replace('/ +/', ' ', trim($stringValue, ' ')), ' ');
+        }
+        return null;
+    }
+
+
+    /**
+     * ASCIICODE
+     *
+     * @param    string    $characters        Value
+     * @return    int
+     */
+    public static function ASCIICODE($characters)
+    {
+        if (($characters === null) || ($characters === '')) {
+            return PHPExcel_Calculation_Functions::VALUE();
+        }
+        $characters    = PHPExcel_Calculation_Functions::flattenSingleValue($characters);
+        if (is_bool($characters)) {
+            if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+                $characters = (int) $characters;
+            } else {
+                $characters = ($characters) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+            }
+        }
+
+        $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::unicodeToOrd($character);
+        } else {
+            if (strlen($characters) > 0) {
+                $character = substr($characters, 0, 1);
+            }
+            return ord($character);
+        }
+    }
+
+
+    /**
+     * CONCATENATE
+     *
+     * @return    string
+     */
+    public static function CONCATENATE()
+    {
+        $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 {
+                    $arg = ($arg) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+                }
+            }
+            $returnValue .= $arg;
+        }
+
+        return $returnValue;
+    }
+
+
+    /**
+     * 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);
+
+        $mask = '$#,##0';
+        if ($decimals > 0) {
+            $mask .= '.' . str_repeat('0', $decimals);
+        } else {
+            $round = pow(10, abs($decimals));
+            if ($value < 0) {
+                $round = 0-$round;
+            }
+            $value = PHPExcel_Calculation_MathTrig::MROUND($value, $round);
+        }
+
+        return PHPExcel_Style_NumberFormat::toFormattedString($value, $mask);
+
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+            }
+
+            if (($offset > 0) && (PHPExcel_Shared_String::CountCharacters($haystack) > $offset)) {
+                if (PHPExcel_Shared_String::CountCharacters($needle) == 0) {
+                    return $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();
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+            }
+
+            if (($offset > 0) && (PHPExcel_Shared_String::CountCharacters($haystack) > $offset)) {
+                if (PHPExcel_Shared_String::CountCharacters($needle) == 0) {
+                    return $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();
+    }
+
+
+    /**
+     * FIXEDFORMAT
+     *
+     * @param    mixed        $value    Value to check
+     * @param    integer        $decimals
+     * @param    boolean        $no_commas
+     * @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);
+
+        // Validate parameters
+        if (!is_numeric($value) || !is_numeric($decimals)) {
+            return PHPExcel_Calculation_Functions::NaN();
+        }
+        $decimals = floor($decimals);
+
+        $valueResult = round($value, $decimals);
+        if ($decimals < 0) {
+            $decimals = 0;
+        }
+        if (!$no_commas) {
+            $valueResult = number_format($valueResult, $decimals);
+        }
+
+        return (string) $valueResult;
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        if (function_exists('mb_substr')) {
+            return mb_substr($value, 0, $chars, 'UTF-8');
+        } else {
+            return substr($value, 0, $chars);
+        }
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        if (function_exists('mb_substr')) {
+            return mb_substr($value, --$start, $chars, 'UTF-8');
+        } else {
+            return substr($value, --$start, $chars);
+        }
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        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);
+        }
+    }
+
+
+    /**
+     * STRINGLENGTH
+     *
+     * @param    string    $value    Value
+     * @return    string
+     */
+    public static function STRINGLENGTH($value = '')
+    {
+        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+        if (is_bool($value)) {
+            $value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        if (function_exists('mb_strlen')) {
+            return mb_strlen($value, 'UTF-8');
+        } else {
+            return strlen($value);
+        }
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        return PHPExcel_Shared_String::StrToLower($mixedCaseString);
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        return PHPExcel_Shared_String::StrToUpper($mixedCaseString);
+    }
+
+
+    /**
+     * 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) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+        }
+
+        return PHPExcel_Shared_String::StrToTitle($mixedCaseString);
+    }
+
+
+    /**
+     * REPLACE
+     *
+     * @param    string    $oldText    String to modify
+     * @param    int        $start        Start character
+     * @param    int        $chars        Number of characters
+     * @param    string    $newText    String to replace in defined position
+     * @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;
+    }
+
+
+    /**
+     * 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 $text;
+    }
+
+
+    /**
+     * RETURNSTRING
+     *
+     * @param    mixed    $testValue    Value to check
+     * @return    boolean
+     */
+    public static function RETURNSTRING($testValue = '')
+    {
+        $testValue = PHPExcel_Calculation_Functions::flattenSingleValue($testValue);
+
+        if (is_string($testValue)) {
+            return $testValue;
+        }
+        return null;
+    }
+
+
+    /**
+     * TEXTFORMAT
+     *
+     * @param    mixed    $value    Value to check
+     * @param    string    $format    Format mask to use
+     * @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);
+    }
+
+    /**
+     * VALUE
+     *
+     * @param    mixed    $value    Value to check
+     * @return    boolean
+     */
+    public static function VALUE($value = '')
+    {
+        $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+        if (!is_numeric($value)) {
+            $numberValue = str_replace(
+                PHPExcel_Shared_String::getThousandsSeparator(),
+                '',
+                trim($value, " \t\n\r\0\x0B" . PHPExcel_Shared_String::getCurrencyCode())
+            );
+            if (is_numeric($numberValue)) {
+                return (float) $numberValue;
+            }
+
+            $dateSetting = PHPExcel_Calculation_Functions::getReturnDateType();
+            PHPExcel_Calculation_Functions::setReturnDateType(PHPExcel_Calculation_Functions::RETURNDATE_EXCEL);
+
+            if (strpos($value, ':') !== false) {
+                $timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($value);
+                if ($timeValue !== PHPExcel_Calculation_Functions::VALUE()) {
+                    PHPExcel_Calculation_Functions::setReturnDateType($dateSetting);
+                    return $timeValue;
+                }
+            }
+            $dateValue = PHPExcel_Calculation_DateTime::DATEVALUE($value);
+            if ($dateValue !== PHPExcel_Calculation_Functions::VALUE()) {
+                PHPExcel_Calculation_Functions::setReturnDateType($dateSetting);
+                return $dateValue;
+            }
+            PHPExcel_Calculation_Functions::setReturnDateType($dateSetting);
+
+            return PHPExcel_Calculation_Functions::VALUE();
+        }
+        return (float) $value;
+    }
+}

+ 111 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/Token/Stack.php

@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * PHPExcel_Calculation_Token_Stack
+ *
+ * Copyright (c) 2006 - 2015 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_Calculation
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation_Token_Stack
+{
+    /**
+     *  The parser stack for formulae
+     *
+     *  @var mixed[]
+     */
+    private $stack = array();
+
+    /**
+     *  Count of entries in the parser stack
+     *
+     *  @var integer
+     */
+    private $count = 0;
+
+    /**
+     * Return the number of entries on the stack
+     *
+     * @return  integer
+     */
+    public function count()
+    {
+        return $this->count;
+    }
+
+    /**
+     * Push a new entry onto the stack
+     *
+     * @param  mixed  $type
+     * @param  mixed  $value
+     * @param  mixed  $reference
+     */
+    public function push($type, $value, $reference = null)
+    {
+        $this->stack[$this->count++] = array(
+            'type'      => $type,
+            'value'     => $value,
+            'reference' => $reference
+        );
+        if ($type == 'Function') {
+            $localeFunction = PHPExcel_Calculation::localeFunc($value);
+            if ($localeFunction != $value) {
+                $this->stack[($this->count - 1)]['localeValue'] = $localeFunction;
+            }
+        }
+    }
+
+    /**
+     * Pop the last entry from the stack
+     *
+     * @return  mixed
+     */
+    public function pop()
+    {
+        if ($this->count > 0) {
+            return $this->stack[--$this->count];
+        }
+        return null;
+    }
+
+    /**
+     * Return an entry from the stack without removing it
+     *
+     * @param   integer  $n  number indicating how far back in the stack we want to look
+     * @return  mixed
+     */
+    public function last($n = 1)
+    {
+        if ($this->count - $n < 0) {
+            return null;
+        }
+        return $this->stack[$this->count - $n];
+    }
+
+    /**
+     * Clear the stack
+     */
+    public function clear()
+    {
+        $this->stack = array();
+        $this->count = 0;
+    }
+}

+ 351 - 0
backend/RTP/extend/excel/PHPExcel/Calculation/functionlist.txt

@@ -0,0 +1,351 @@
+ABS
+ACCRINT
+ACCRINTM
+ACOS
+ACOSH
+ADDRESS
+AMORDEGRC
+AMORLINC
+AND
+AREAS
+ASC
+ASIN
+ASINH
+ATAN
+ATAN2
+ATANH
+AVEDEV
+AVERAGE
+AVERAGEA
+AVERAGEIF
+AVERAGEIFS
+BAHTTEXT
+BESSELI
+BESSELJ
+BESSELK
+BESSELY
+BETADIST
+BETAINV
+BIN2DEC
+BIN2HEX
+BIN2OCT
+BINOMDIST
+CEILING
+CELL
+CHAR
+CHIDIST
+CHIINV
+CHITEST
+CHOOSE
+CLEAN
+CODE
+COLUMN
+COLUMNS
+COMBIN
+COMPLEX
+CONCATENATE
+CONFIDENCE
+CONVERT
+CORREL
+COS
+COSH
+COUNT
+COUNTA
+COUNTBLANK
+COUNTIF
+COUNTIFS
+COUPDAYBS
+COUPDAYBS
+COUPDAYSNC
+COUPNCD
+COUPNUM
+COUPPCD
+COVAR
+CRITBINOM
+CUBEKPIMEMBER
+CUBEMEMBER
+CUBEMEMBERPROPERTY
+CUBERANKEDMEMBER
+CUBESET
+CUBESETCOUNT
+CUBEVALUE
+CUMIPMT
+CUMPRINC
+DATE
+DATEDIF
+DATEVALUE
+DAVERAGE
+DAY
+DAYS360
+DB
+DCOUNT
+DCOUNTA
+DDB
+DEC2BIN
+DEC2HEX
+DEC2OCT
+DEGREES
+DELTA
+DEVSQ
+DGET
+DISC
+DMAX
+DMIN
+DOLLAR
+DOLLARDE
+DOLLARFR
+DPRODUCT
+DSTDEV
+DSTDEVP
+DSUM
+DURATION
+DVAR
+DVARP
+EDATE
+EFFECT
+EOMONTH
+ERF
+ERFC
+ERROR.TYPE
+EVEN
+EXACT
+EXP
+EXPONDIST
+FACT
+FACTDOUBLE
+FALSE
+FDIST
+FIND
+FINDB
+FINV
+FISHER
+FISHERINV
+FIXED
+FLOOR
+FORECAST
+FREQUENCY
+FTEST
+FV
+FVSCHEDULE
+GAMAMDIST
+GAMMAINV
+GAMMALN
+GCD
+GEOMEAN
+GESTEP
+GETPIVOTDATA
+GROWTH
+HARMEAN
+HEX2BIN
+HEX2OCT
+HLOOKUP
+HOUR
+HYPERLINK
+HYPGEOMDIST
+IF
+IFERROR
+IMABS
+IMAGINARY
+IMARGUMENT
+IMCONJUGATE
+IMCOS
+IMEXP
+IMLN
+IMLOG10
+IMLOG2
+IMPOWER
+IMPRODUCT
+IMREAL
+IMSIN
+IMSQRT
+IMSUB
+IMSUM
+INDEX
+INDIRECT
+INFO
+INT
+INTERCEPT
+INTRATE
+IPMT
+IRR
+ISBLANK
+ISERR
+ISERROR
+ISEVEN
+ISLOGICAL
+ISNA
+ISNONTEXT
+ISNUMBER
+ISODD
+ISPMT
+ISREF
+ISTEXT
+JIS
+KURT
+LARGE
+LCM
+LEFT
+LEFTB
+LEN
+LENB
+LINEST
+LN
+LOG
+LOG10
+LOGEST
+LOGINV
+LOGNORMDIST
+LOOKUP
+LOWER
+MATCH
+MAX
+MAXA
+MDETERM
+MDURATION
+MEDIAN
+MID
+MIDB
+MIN
+MINA
+MINUTE
+MINVERSE
+MIRR
+MMULT
+MOD
+MODE
+MONTH
+MROUND
+MULTINOMIAL
+N
+NA
+NEGBINOMDIST
+NETWORKDAYS
+NOMINAL
+NORMDIST
+NORMINV
+NORMSDIST
+NORMSINV
+NOT
+NOW
+NPER
+NPV
+OCT2BIN
+OCT2DEC
+OCT2HEX
+ODD
+ODDFPRICE
+ODDFYIELD
+ODDLPRICE
+ODDLYIELD
+OFFSET
+OR
+PEARSON
+PERCENTILE
+PERCENTRANK
+PERMUT
+PHONETIC
+PI
+PMT
+POISSON
+POWER
+PPMT
+PRICE
+PRICEDISC
+PRICEMAT
+PROB
+PRODUCT
+PROPER
+PV
+QUARTILE
+QUOTIENT
+RADIANS
+RAND
+RANDBETWEEN
+RANK
+RATE
+RECEIVED
+REPLACE
+REPLACEB
+REPT
+RIGHT
+RIGHTB
+ROMAN
+ROUND
+ROUNDDOWN
+ROUNDUP
+ROW
+ROWS
+RSQ
+RTD
+SEARCH
+SEARCHB
+SECOND
+SERIESSUM
+SIGN
+SIN
+SINH
+SKEW
+SLN
+SLOPE
+SMALL
+SQRT
+SQRTPI
+STANDARDIZE
+STDEV
+STDEVA
+STDEVP
+STDEVPA
+STEYX
+SUBSTITUTE
+SUBTOTAL
+SUM
+SUMIF
+SUMIFS
+SUMPRODUCT
+SUMSQ
+SUMX2MY2
+SUMX2PY2
+SUMXMY2
+SYD
+T
+TAN
+TANH
+TBILLEQ
+TBILLPRICE
+TBILLYIELD
+TDIST
+TEXT
+TIME
+TIMEVALUE
+TINV
+TODAY
+TRANSPOSE
+TREND
+TRIM
+TRIMMEAN
+TRUE
+TRUNC
+TTEST
+TYPE
+UPPER
+USDOLLAR
+VALUE
+VAR
+VARA
+VARP
+VARPA
+VDB
+VERSION
+VLOOKUP
+WEEKDAY
+WEEKNUM
+WEIBULL
+WORKDAY
+XIRR
+XNPV
+YEAR
+YEARFRAC
+YIELD
+YIELDDISC
+YIELDMAT
+ZTEST

File diff suppressed because it is too large
+ 1032 - 0
backend/RTP/extend/excel/PHPExcel/Cell.php


+ 187 - 0
backend/RTP/extend/excel/PHPExcel/Cell/AdvancedValueBinder.php

@@ -0,0 +1,187 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Cell_AdvancedValueBinder
+ *
+ * Copyright (c) 2006 - 2015 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_Cell
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
+{
+    /**
+     * Bind value to a cell
+     *
+     * @param  PHPExcel_Cell  $cell  Cell to bind value to
+     * @param  mixed $value          Value to bind in cell
+     * @return boolean
+     */
+    public function bindValue(PHPExcel_Cell $cell, $value = null)
+    {
+        // sanitize UTF-8 strings
+        if (is_string($value)) {
+            $value = PHPExcel_Shared_String::SanitizeUTF8($value);
+        }
+
+        // Find out data type
+        $dataType = parent::dataTypeForValue($value);
+
+        // 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 fraction
+            if (preg_match('/^([+-]?)\s*([0-9]+)\s?\/\s*([0-9]+)$/', $value, $matches)) {
+                // Convert value to number
+                $value = $matches[2] / $matches[3];
+                if ($matches[1] == '-') {
+                    $value = 0 - $value;
+                }
+                $cell->setValueExplicit((float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+                // Set style
+                $cell->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getNumberFormat()->setFormatCode('??/??');
+                return true;
+            } elseif (preg_match('/^([+-]?)([0-9]*) +([0-9]*)\s?\/\s*([0-9]*)$/', $value, $matches)) {
+                // Convert value to number
+                $value = $matches[2] + ($matches[3] / $matches[4]);
+                if ($matches[1] == '-') {
+                    $value = 0 - $value;
+                }
+                $cell->setValueExplicit((float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+                // Set style
+                $cell->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getNumberFormat()->setFormatCode('# ??/??');
+                return true;
+            }
+
+            // Check for percentage
+            if (preg_match('/^\-?[0-9]*\.?[0-9]*\s?\%$/', $value)) {
+                // Convert value to number
+                $value = (float) str_replace('%', '', $value) / 100;
+                $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+                // Set style
+                $cell->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00);
+                return true;
+            }
+
+            // Check for currency
+            $currencyCode = PHPExcel_Shared_String::getCurrencyCode();
+            $decimalSeparator = PHPExcel_Shared_String::getDecimalSeparator();
+            $thousandsSeparator = PHPExcel_Shared_String::getThousandsSeparator();
+            if (preg_match('/^'.preg_quote($currencyCode).' *(\d{1,3}('.preg_quote($thousandsSeparator).'\d{3})*|(\d+))('.preg_quote($decimalSeparator).'\d{2})?$/', $value)) {
+                // Convert value to number
+                $value = (float) trim(str_replace(array($currencyCode, $thousandsSeparator, $decimalSeparator), array('', '', '.'), $value));
+                $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+                // Set style
+                $cell->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getNumberFormat()->setFormatCode(
+                        str_replace('$', $currencyCode, PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE)
+                    );
+                return true;
+            } elseif (preg_match('/^\$ *(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/', $value)) {
+                // Convert value to number
+                $value = (float) trim(str_replace(array('$',','), '', $value));
+                $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+                // Set style
+                $cell->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
+                return true;
+            }
+
+            // Check for time without seconds e.g. '9:45', '09:45'
+            if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) {
+                // Convert value to number
+                list($h, $m) = explode(':', $value);
+                $days = $h / 24 + $m / 1440;
+                $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+                // Set style
+                $cell->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3);
+                return true;
+            }
+
+            // Check for time with seconds '9:45:59', '09:45:59'
+            if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) {
+                // Convert value to number
+                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->getWorksheet()->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 (($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->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getNumberFormat()->setFormatCode($formatCode);
+                return true;
+            }
+
+            // Check for newline character "\n"
+            if (strpos($value, "\n") !== false) {
+                $value = PHPExcel_Shared_String::SanitizeUTF8($value);
+                $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
+                // Set style
+                $cell->getWorksheet()->getStyle($cell->getCoordinate())
+                    ->getAlignment()->setWrapText(true);
+                return true;
+            }
+        }
+
+        // Not bound yet? Use parent...
+        return parent::bindValue($cell, $value);
+    }
+}

+ 115 - 0
backend/RTP/extend/excel/PHPExcel/Cell/DataType.php

@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * PHPExcel_Cell_DataType
+ *
+ * Copyright (c) 2006 - 2015 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_Cell
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Cell_DataType
+{
+    /* Data types */
+    const TYPE_STRING2  = 'str';
+    const TYPE_STRING   = 's';
+    const TYPE_FORMULA  = 'f';
+    const TYPE_NUMERIC  = 'n';
+    const TYPE_BOOL     = 'b';
+    const TYPE_NULL     = 'null';
+    const TYPE_INLINE   = 'inlineStr';
+    const TYPE_ERROR    = 'e';
+
+    /**
+     * List of error codes
+     *
+     * @var array
+     */
+    private static $errorCodes = array(
+        '#NULL!'  => 0,
+        '#DIV/0!' => 1,
+        '#VALUE!' => 2,
+        '#REF!'   => 3,
+        '#NAME?'  => 4,
+        '#NUM!'   => 5,
+        '#N/A'    => 6
+    );
+
+    /**
+     * Get list of error codes
+     *
+     * @return array
+     */
+    public static function getErrorCodes()
+    {
+        return self::$errorCodes;
+    }
+
+    /**
+     * DataType for value
+     *
+     * @deprecated  Replaced by PHPExcel_Cell_IValueBinder infrastructure, will be removed in version 1.8.0
+     * @param       mixed  $pValue
+     * @return      string
+     */
+    public static function dataTypeForValue($pValue = null)
+    {
+        return PHPExcel_Cell_DefaultValueBinder::dataTypeForValue($pValue);
+    }
+
+    /**
+     * Check a string that it satisfies Excel requirements
+     *
+     * @param  mixed  Value to sanitize to an Excel string
+     * @return mixed  Sanitized value
+     */
+    public static function checkString($pValue = null)
+    {
+        if ($pValue instanceof PHPExcel_RichText) {
+            // TODO: Sanitize Rich-Text string (max. character count is 32,767)
+            return $pValue;
+        }
+
+        // string must never be longer than 32,767 characters, truncate if necessary
+        $pValue = PHPExcel_Shared_String::Substring($pValue, 0, 32767);
+
+        // we require that newline is represented as "\n" in core, not as "\r\n" or "\r"
+        $pValue = str_replace(array("\r\n", "\r"), "\n", $pValue);
+
+        return $pValue;
+    }
+
+    /**
+     * Check a value that it is a valid error code
+     *
+     * @param  mixed   Value to sanitize to an Excel error code
+     * @return string  Sanitized value
+     */
+    public static function checkErrorCode($pValue = null)
+    {
+        $pValue = (string) $pValue;
+
+        if (!array_key_exists($pValue, self::$errorCodes)) {
+            $pValue = '#NULL!';
+        }
+
+        return $pValue;
+    }
+}

+ 492 - 0
backend/RTP/extend/excel/PHPExcel/Cell/DataValidation.php

@@ -0,0 +1,492 @@
+<?php
+
+/**
+ * PHPExcel_Cell_DataValidation
+ *
+ * Copyright (c) 2006 - 2015 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_Cell
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Cell_DataValidation
+{
+    /* Data validation types */
+    const TYPE_NONE        = 'none';
+    const TYPE_CUSTOM      = 'custom';
+    const TYPE_DATE        = 'date';
+    const TYPE_DECIMAL     = 'decimal';
+    const TYPE_LIST        = 'list';
+    const TYPE_TEXTLENGTH  = 'textLength';
+    const TYPE_TIME        = 'time';
+    const TYPE_WHOLE       = 'whole';
+
+    /* Data validation error styles */
+    const STYLE_STOP         = 'stop';
+    const STYLE_WARNING      = 'warning';
+    const STYLE_INFORMATION  = 'information';
+
+    /* Data validation operators */
+    const OPERATOR_BETWEEN             = 'between';
+    const OPERATOR_EQUAL               = 'equal';
+    const OPERATOR_GREATERTHAN         = 'greaterThan';
+    const OPERATOR_GREATERTHANOREQUAL  = 'greaterThanOrEqual';
+    const OPERATOR_LESSTHAN            = 'lessThan';
+    const OPERATOR_LESSTHANOREQUAL     = 'lessThanOrEqual';
+    const OPERATOR_NOTBETWEEN          = 'notBetween';
+    const OPERATOR_NOTEQUAL            = 'notEqual';
+
+    /**
+     * Formula 1
+     *
+     * @var string
+     */
+    private $formula1;
+
+    /**
+     * Formula 2
+     *
+     * @var string
+     */
+    private $formula2;
+
+    /**
+     * Type
+     *
+     * @var string
+     */
+    private $type = PHPExcel_Cell_DataValidation::TYPE_NONE;
+
+    /**
+     * Error style
+     *
+     * @var string
+     */
+    private $errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP;
+
+    /**
+     * Operator
+     *
+     * @var string
+     */
+    private $operator;
+
+    /**
+     * Allow Blank
+     *
+     * @var boolean
+     */
+    private $allowBlank;
+
+    /**
+     * Show DropDown
+     *
+     * @var boolean
+     */
+    private $showDropDown;
+
+    /**
+     * Show InputMessage
+     *
+     * @var boolean
+     */
+    private $showInputMessage;
+
+    /**
+     * Show ErrorMessage
+     *
+     * @var boolean
+     */
+    private $showErrorMessage;
+
+    /**
+     * Error title
+     *
+     * @var string
+     */
+    private $errorTitle;
+
+    /**
+     * Error
+     *
+     * @var string
+     */
+    private $error;
+
+    /**
+     * Prompt title
+     *
+     * @var string
+     */
+    private $promptTitle;
+
+    /**
+     * Prompt
+     *
+     * @var string
+     */
+    private $prompt;
+
+    /**
+     * Create a new PHPExcel_Cell_DataValidation
+     */
+    public function __construct()
+    {
+        // Initialise member variables
+        $this->formula1          = '';
+        $this->formula2          = '';
+        $this->type              = PHPExcel_Cell_DataValidation::TYPE_NONE;
+        $this->errorStyle        = PHPExcel_Cell_DataValidation::STYLE_STOP;
+        $this->operator          = '';
+        $this->allowBlank        = false;
+        $this->showDropDown      = false;
+        $this->showInputMessage  = false;
+        $this->showErrorMessage  = false;
+        $this->errorTitle        = '';
+        $this->error             = '';
+        $this->promptTitle       = '';
+        $this->prompt            = '';
+    }
+
+    /**
+     * Get Formula 1
+     *
+     * @return string
+     */
+    public function getFormula1()
+    {
+        return $this->formula1;
+    }
+
+    /**
+     * Set Formula 1
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setFormula1($value = '')
+    {
+        $this->formula1 = $value;
+        return $this;
+    }
+
+    /**
+     * Get Formula 2
+     *
+     * @return string
+     */
+    public function getFormula2()
+    {
+        return $this->formula2;
+    }
+
+    /**
+     * Set Formula 2
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setFormula2($value = '')
+    {
+        $this->formula2 = $value;
+        return $this;
+    }
+
+    /**
+     * Get Type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Set Type
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setType($value = PHPExcel_Cell_DataValidation::TYPE_NONE)
+    {
+        $this->type = $value;
+        return $this;
+    }
+
+    /**
+     * Get Error style
+     *
+     * @return string
+     */
+    public function getErrorStyle()
+    {
+        return $this->errorStyle;
+    }
+
+    /**
+     * Set Error style
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setErrorStyle($value = PHPExcel_Cell_DataValidation::STYLE_STOP)
+    {
+        $this->errorStyle = $value;
+        return $this;
+    }
+
+    /**
+     * Get Operator
+     *
+     * @return string
+     */
+    public function getOperator()
+    {
+        return $this->operator;
+    }
+
+    /**
+     * Set Operator
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setOperator($value = '')
+    {
+        $this->operator = $value;
+        return $this;
+    }
+
+    /**
+     * Get Allow Blank
+     *
+     * @return boolean
+     */
+    public function getAllowBlank()
+    {
+        return $this->allowBlank;
+    }
+
+    /**
+     * Set Allow Blank
+     *
+     * @param  boolean    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setAllowBlank($value = false)
+    {
+        $this->allowBlank = $value;
+        return $this;
+    }
+
+    /**
+     * Get Show DropDown
+     *
+     * @return boolean
+     */
+    public function getShowDropDown()
+    {
+        return $this->showDropDown;
+    }
+
+    /**
+     * Set Show DropDown
+     *
+     * @param  boolean    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setShowDropDown($value = false)
+    {
+        $this->showDropDown = $value;
+        return $this;
+    }
+
+    /**
+     * Get Show InputMessage
+     *
+     * @return boolean
+     */
+    public function getShowInputMessage()
+    {
+        return $this->showInputMessage;
+    }
+
+    /**
+     * Set Show InputMessage
+     *
+     * @param  boolean    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setShowInputMessage($value = false)
+    {
+        $this->showInputMessage = $value;
+        return $this;
+    }
+
+    /**
+     * Get Show ErrorMessage
+     *
+     * @return boolean
+     */
+    public function getShowErrorMessage()
+    {
+        return $this->showErrorMessage;
+    }
+
+    /**
+     * Set Show ErrorMessage
+     *
+     * @param  boolean    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setShowErrorMessage($value = false)
+    {
+        $this->showErrorMessage = $value;
+        return $this;
+    }
+
+    /**
+     * Get Error title
+     *
+     * @return string
+     */
+    public function getErrorTitle()
+    {
+        return $this->errorTitle;
+    }
+
+    /**
+     * Set Error title
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setErrorTitle($value = '')
+    {
+        $this->errorTitle = $value;
+        return $this;
+    }
+
+    /**
+     * Get Error
+     *
+     * @return string
+     */
+    public function getError()
+    {
+        return $this->error;
+    }
+
+    /**
+     * Set Error
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setError($value = '')
+    {
+        $this->error = $value;
+        return $this;
+    }
+
+    /**
+     * Get Prompt title
+     *
+     * @return string
+     */
+    public function getPromptTitle()
+    {
+        return $this->promptTitle;
+    }
+
+    /**
+     * Set Prompt title
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setPromptTitle($value = '')
+    {
+        $this->promptTitle = $value;
+        return $this;
+    }
+
+    /**
+     * Get Prompt
+     *
+     * @return string
+     */
+    public function getPrompt()
+    {
+        return $this->prompt;
+    }
+
+    /**
+     * Set Prompt
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_DataValidation
+     */
+    public function setPrompt($value = '')
+    {
+        $this->prompt = $value;
+        return $this;
+    }
+
+    /**
+     * Get hash code
+     *
+     * @return string    Hash code
+     */
+    public function getHashCode()
+    {
+        return md5(
+            $this->formula1 .
+            $this->formula2 .
+            $this->type = PHPExcel_Cell_DataValidation::TYPE_NONE .
+            $this->errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP .
+            $this->operator .
+            ($this->allowBlank ? 't' : 'f') .
+            ($this->showDropDown ? 't' : 'f') .
+            ($this->showInputMessage ? 't' : 'f') .
+            ($this->showErrorMessage ? 't' : 'f') .
+            $this->errorTitle .
+            $this->error .
+            $this->promptTitle .
+            $this->prompt .
+            __CLASS__
+        );
+    }
+
+    /**
+     * 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)) {
+                $this->$key = clone $value;
+            } else {
+                $this->$key = $value;
+            }
+        }
+    }
+}

+ 102 - 0
backend/RTP/extend/excel/PHPExcel/Cell/DefaultValueBinder.php

@@ -0,0 +1,102 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Cell_DefaultValueBinder
+ *
+ * Copyright (c) 2006 - 2015 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_Cell
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
+{
+    /**
+     * Bind value to a cell
+     *
+     * @param  PHPExcel_Cell  $cell   Cell to bind value to
+     * @param  mixed          $value  Value to bind in cell
+     * @return boolean
+     */
+    public function bindValue(PHPExcel_Cell $cell, $value = null)
+    {
+        // sanitize UTF-8 strings
+        if (is_string($value)) {
+            $value = PHPExcel_Shared_String::SanitizeUTF8($value);
+        } elseif (is_object($value)) {
+            // Handle any objects that might be injected
+            if ($value instanceof DateTime) {
+                $value = $value->format('Y-m-d H:i:s');
+            } elseif (!($value instanceof PHPExcel_RichText)) {
+                $value = (string) $value;
+            }
+        }
+
+        // Set value explicit
+        $cell->setValueExplicit($value, self::dataTypeForValue($value));
+
+        // Done!
+        return true;
+    }
+
+    /**
+     * DataType for value
+     *
+     * @param   mixed  $pValue
+     * @return  string
+     */
+    public static function dataTypeForValue($pValue = null)
+    {
+        // Match the value against a few data types
+        if ($pValue === null) {
+            return PHPExcel_Cell_DataType::TYPE_NULL;
+        } elseif ($pValue === '') {
+            return PHPExcel_Cell_DataType::TYPE_STRING;
+        } elseif ($pValue instanceof PHPExcel_RichText) {
+            return PHPExcel_Cell_DataType::TYPE_INLINE;
+        } elseif ($pValue{0} === '=' && strlen($pValue) > 1) {
+            return PHPExcel_Cell_DataType::TYPE_FORMULA;
+        } elseif (is_bool($pValue)) {
+            return PHPExcel_Cell_DataType::TYPE_BOOL;
+        } elseif (is_float($pValue) || is_int($pValue)) {
+            return PHPExcel_Cell_DataType::TYPE_NUMERIC;
+        } elseif (preg_match('/^[\+\-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $pValue)) {
+            $tValue = ltrim($pValue, '+-');
+            if (is_string($pValue) && $tValue{0} === '0' && strlen($tValue) > 1 && $tValue{1} !== '.') {
+                return PHPExcel_Cell_DataType::TYPE_STRING;
+            } elseif ((strpos($pValue, '.') === false) && ($pValue > PHP_INT_MAX)) {
+                return PHPExcel_Cell_DataType::TYPE_STRING;
+            }
+            return PHPExcel_Cell_DataType::TYPE_NUMERIC;
+        } elseif (is_string($pValue) && array_key_exists($pValue, PHPExcel_Cell_DataType::getErrorCodes())) {
+            return PHPExcel_Cell_DataType::TYPE_ERROR;
+        }
+
+        return PHPExcel_Cell_DataType::TYPE_STRING;
+    }
+}

+ 124 - 0
backend/RTP/extend/excel/PHPExcel/Cell/Hyperlink.php

@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * PHPExcel_Cell_Hyperlink
+ *
+ * Copyright (c) 2006 - 2015 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_Cell
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Cell_Hyperlink
+{
+    /**
+     * URL to link the cell to
+     *
+     * @var string
+     */
+    private $url;
+
+    /**
+     * Tooltip to display on the hyperlink
+     *
+     * @var string
+     */
+    private $tooltip;
+
+    /**
+     * Create a new PHPExcel_Cell_Hyperlink
+     *
+     * @param  string  $pUrl      Url to link the cell to
+     * @param  string  $pTooltip  Tooltip to display on the hyperlink
+     */
+    public function __construct($pUrl = '', $pTooltip = '')
+    {
+        // Initialise member variables
+        $this->url     = $pUrl;
+        $this->tooltip = $pTooltip;
+    }
+
+    /**
+     * Get URL
+     *
+     * @return string
+     */
+    public function getUrl()
+    {
+        return $this->url;
+    }
+
+    /**
+     * Set URL
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_Hyperlink
+     */
+    public function setUrl($value = '')
+    {
+        $this->url = $value;
+        return $this;
+    }
+
+    /**
+     * Get tooltip
+     *
+     * @return string
+     */
+    public function getTooltip()
+    {
+        return $this->tooltip;
+    }
+
+    /**
+     * Set tooltip
+     *
+     * @param  string    $value
+     * @return PHPExcel_Cell_Hyperlink
+     */
+    public function setTooltip($value = '')
+    {
+        $this->tooltip = $value;
+        return $this;
+    }
+
+    /**
+     * Is this hyperlink internal? (to another worksheet)
+     *
+     * @return boolean
+     */
+    public function isInternal()
+    {
+        return strpos($this->url, 'sheet://') !== false;
+    }
+
+    /**
+     * Get hash code
+     *
+     * @return string    Hash code
+     */
+    public function getHashCode()
+    {
+        return md5(
+            $this->url .
+            $this->tooltip .
+            __CLASS__
+        );
+    }
+}

+ 47 - 0
backend/RTP/extend/excel/PHPExcel/Cell/IValueBinder.php

@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2015 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_Cell
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+
+
+/**
+ * PHPExcel_Cell_IValueBinder
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Cell
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+interface PHPExcel_Cell_IValueBinder
+{
+    /**
+     * Bind value to a cell
+     *
+     * @param  PHPExcel_Cell $cell    Cell to bind value to
+     * @param  mixed $value           Value to bind in cell
+     * @return boolean
+     */
+    public function bindValue(PHPExcel_Cell $cell, $value = null);
+}

+ 680 - 0
backend/RTP/extend/excel/PHPExcel/Chart.php

@@ -0,0 +1,680 @@
+<?php
+
+/**
+ * PHPExcel_Chart
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Chart
+{
+    /**
+     * Chart Name
+     *
+     * @var string
+     */
+    private $name = '';
+
+    /**
+     * Worksheet
+     *
+     * @var PHPExcel_Worksheet
+     */
+    private $worksheet;
+
+    /**
+     * Chart Title
+     *
+     * @var PHPExcel_Chart_Title
+     */
+    private $title;
+
+    /**
+     * Chart Legend
+     *
+     * @var PHPExcel_Chart_Legend
+     */
+    private $legend;
+
+    /**
+     * X-Axis Label
+     *
+     * @var PHPExcel_Chart_Title
+     */
+    private $xAxisLabel;
+
+    /**
+     * Y-Axis Label
+     *
+     * @var PHPExcel_Chart_Title
+     */
+    private $yAxisLabel;
+
+    /**
+     * Chart Plot Area
+     *
+     * @var PHPExcel_Chart_PlotArea
+     */
+    private $plotArea;
+
+    /**
+     * Plot Visible Only
+     *
+     * @var boolean
+     */
+    private $plotVisibleOnly = true;
+
+    /**
+     * Display Blanks as
+     *
+     * @var string
+     */
+    private $displayBlanksAs = '0';
+
+    /**
+     * Chart Asix Y as
+     *
+     * @var PHPExcel_Chart_Axis
+     */
+    private $yAxis;
+
+    /**
+     * Chart Asix X as
+     *
+     * @var PHPExcel_Chart_Axis
+     */
+    private $xAxis;
+
+    /**
+     * Chart Major Gridlines as
+     *
+     * @var PHPExcel_Chart_GridLines
+     */
+    private $majorGridlines;
+
+    /**
+     * Chart Minor Gridlines as
+     *
+     * @var PHPExcel_Chart_GridLines
+     */
+    private $minorGridlines;
+
+    /**
+     * Top-Left Cell Position
+     *
+     * @var string
+     */
+    private $topLeftCellRef = 'A1';
+
+
+    /**
+     * Top-Left X-Offset
+     *
+     * @var integer
+     */
+    private $topLeftXOffset = 0;
+
+
+    /**
+     * Top-Left Y-Offset
+     *
+     * @var integer
+     */
+    private $topLeftYOffset = 0;
+
+
+    /**
+     * Bottom-Right Cell Position
+     *
+     * @var string
+     */
+    private $bottomRightCellRef = 'A1';
+
+
+    /**
+     * Bottom-Right X-Offset
+     *
+     * @var integer
+     */
+    private $bottomRightXOffset = 10;
+
+
+    /**
+     * Bottom-Right Y-Offset
+     *
+     * @var integer
+     */
+    private $bottomRightYOffset = 10;
+
+
+    /**
+     * Create a new PHPExcel_Chart
+     */
+    public function __construct($name, PHPExcel_Chart_Title $title = null, PHPExcel_Chart_Legend $legend = null, PHPExcel_Chart_PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = '0', PHPExcel_Chart_Title $xAxisLabel = null, PHPExcel_Chart_Title $yAxisLabel = null, PHPExcel_Chart_Axis $xAxis = null, PHPExcel_Chart_Axis $yAxis = null, PHPExcel_Chart_GridLines $majorGridlines = null, PHPExcel_Chart_GridLines $minorGridlines = null)
+    {
+        $this->name = $name;
+        $this->title = $title;
+        $this->legend = $legend;
+        $this->xAxisLabel = $xAxisLabel;
+        $this->yAxisLabel = $yAxisLabel;
+        $this->plotArea = $plotArea;
+        $this->plotVisibleOnly = $plotVisibleOnly;
+        $this->displayBlanksAs = $displayBlanksAs;
+        $this->xAxis = $xAxis;
+        $this->yAxis = $yAxis;
+        $this->majorGridlines = $majorGridlines;
+        $this->minorGridlines = $minorGridlines;
+    }
+
+    /**
+     * Get Name
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Get Worksheet
+     *
+     * @return PHPExcel_Worksheet
+     */
+    public function getWorksheet()
+    {
+        return $this->worksheet;
+    }
+
+    /**
+     * Set Worksheet
+     *
+     * @param    PHPExcel_Worksheet    $pValue
+     * @throws    PHPExcel_Chart_Exception
+     * @return PHPExcel_Chart
+     */
+    public function setWorksheet(PHPExcel_Worksheet $pValue = null)
+    {
+        $this->worksheet = $pValue;
+
+        return $this;
+    }
+
+    /**
+     * Get Title
+     *
+     * @return PHPExcel_Chart_Title
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * Set Title
+     *
+     * @param    PHPExcel_Chart_Title $title
+     * @return    PHPExcel_Chart
+     */
+    public function setTitle(PHPExcel_Chart_Title $title)
+    {
+        $this->title = $title;
+
+        return $this;
+    }
+
+    /**
+     * Get Legend
+     *
+     * @return PHPExcel_Chart_Legend
+     */
+    public function getLegend()
+    {
+        return $this->legend;
+    }
+
+    /**
+     * Set Legend
+     *
+     * @param    PHPExcel_Chart_Legend $legend
+     * @return    PHPExcel_Chart
+     */
+    public function setLegend(PHPExcel_Chart_Legend $legend)
+    {
+        $this->legend = $legend;
+
+        return $this;
+    }
+
+    /**
+     * Get X-Axis Label
+     *
+     * @return PHPExcel_Chart_Title
+     */
+    public function getXAxisLabel()
+    {
+        return $this->xAxisLabel;
+    }
+
+    /**
+     * Set X-Axis Label
+     *
+     * @param    PHPExcel_Chart_Title $label
+     * @return    PHPExcel_Chart
+     */
+    public function setXAxisLabel(PHPExcel_Chart_Title $label)
+    {
+        $this->xAxisLabel = $label;
+
+        return $this;
+    }
+
+    /**
+     * Get Y-Axis Label
+     *
+     * @return PHPExcel_Chart_Title
+     */
+    public function getYAxisLabel()
+    {
+        return $this->yAxisLabel;
+    }
+
+    /**
+     * Set Y-Axis Label
+     *
+     * @param    PHPExcel_Chart_Title $label
+     * @return    PHPExcel_Chart
+     */
+    public function setYAxisLabel(PHPExcel_Chart_Title $label)
+    {
+        $this->yAxisLabel = $label;
+
+        return $this;
+    }
+
+    /**
+     * Get Plot Area
+     *
+     * @return PHPExcel_Chart_PlotArea
+     */
+    public function getPlotArea()
+    {
+        return $this->plotArea;
+    }
+
+    /**
+     * Get Plot Visible Only
+     *
+     * @return boolean
+     */
+    public function getPlotVisibleOnly()
+    {
+        return $this->plotVisibleOnly;
+    }
+
+    /**
+     * Set Plot Visible Only
+     *
+     * @param boolean $plotVisibleOnly
+     * @return PHPExcel_Chart
+     */
+    public function setPlotVisibleOnly($plotVisibleOnly = true)
+    {
+        $this->plotVisibleOnly = $plotVisibleOnly;
+
+        return $this;
+    }
+
+    /**
+     * Get Display Blanks as
+     *
+     * @return string
+     */
+    public function getDisplayBlanksAs()
+    {
+        return $this->displayBlanksAs;
+    }
+
+    /**
+     * Set Display Blanks as
+     *
+     * @param string $displayBlanksAs
+     * @return PHPExcel_Chart
+     */
+    public function setDisplayBlanksAs($displayBlanksAs = '0')
+    {
+        $this->displayBlanksAs = $displayBlanksAs;
+    }
+
+
+    /**
+     * Get yAxis
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    public function getChartAxisY()
+    {
+        if ($this->yAxis !== null) {
+            return $this->yAxis;
+        }
+
+        return new PHPExcel_Chart_Axis();
+    }
+
+    /**
+     * Get xAxis
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    public function getChartAxisX()
+    {
+        if ($this->xAxis !== null) {
+            return $this->xAxis;
+        }
+
+        return new PHPExcel_Chart_Axis();
+    }
+
+    /**
+     * Get Major Gridlines
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+    public function getMajorGridlines()
+    {
+        if ($this->majorGridlines !== null) {
+            return $this->majorGridlines;
+        }
+
+        return new PHPExcel_Chart_GridLines();
+    }
+
+    /**
+     * Get Minor Gridlines
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+    public function getMinorGridlines()
+    {
+        if ($this->minorGridlines !== null) {
+            return $this->minorGridlines;
+        }
+
+        return new PHPExcel_Chart_GridLines();
+    }
+
+
+    /**
+     * Set the Top Left position for the chart
+     *
+     * @param    string    $cell
+     * @param    integer    $xOffset
+     * @param    integer    $yOffset
+     * @return PHPExcel_Chart
+     */
+    public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
+    {
+        $this->topLeftCellRef = $cell;
+        if (!is_null($xOffset)) {
+            $this->setTopLeftXOffset($xOffset);
+        }
+        if (!is_null($yOffset)) {
+            $this->setTopLeftYOffset($yOffset);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get the top left position of the chart
+     *
+     * @return array    an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+     */
+    public function getTopLeftPosition()
+    {
+        return array(
+            'cell'    => $this->topLeftCellRef,
+            'xOffset' => $this->topLeftXOffset,
+            'yOffset' => $this->topLeftYOffset
+        );
+    }
+
+    /**
+     * Get the cell address where the top left of the chart is fixed
+     *
+     * @return string
+     */
+    public function getTopLeftCell()
+    {
+        return $this->topLeftCellRef;
+    }
+
+    /**
+     * Set the Top Left cell position for the chart
+     *
+     * @param    string    $cell
+     * @return PHPExcel_Chart
+     */
+    public function setTopLeftCell($cell)
+    {
+        $this->topLeftCellRef = $cell;
+
+        return $this;
+    }
+
+    /**
+     * Set the offset position within the Top Left cell for the chart
+     *
+     * @param    integer    $xOffset
+     * @param    integer    $yOffset
+     * @return PHPExcel_Chart
+     */
+    public function setTopLeftOffset($xOffset = null, $yOffset = null)
+    {
+        if (!is_null($xOffset)) {
+            $this->setTopLeftXOffset($xOffset);
+        }
+        if (!is_null($yOffset)) {
+            $this->setTopLeftYOffset($yOffset);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get the offset position within the Top Left cell for the chart
+     *
+     * @return integer[]
+     */
+    public function getTopLeftOffset()
+    {
+        return array(
+            'X' => $this->topLeftXOffset,
+            'Y' => $this->topLeftYOffset
+        );
+    }
+
+    public function setTopLeftXOffset($xOffset)
+    {
+        $this->topLeftXOffset = $xOffset;
+
+        return $this;
+    }
+
+    public function getTopLeftXOffset()
+    {
+        return $this->topLeftXOffset;
+    }
+
+    public function setTopLeftYOffset($yOffset)
+    {
+        $this->topLeftYOffset = $yOffset;
+
+        return $this;
+    }
+
+    public function getTopLeftYOffset()
+    {
+        return $this->topLeftYOffset;
+    }
+
+    /**
+     * Set the Bottom Right position of the chart
+     *
+     * @param    string    $cell
+     * @param    integer    $xOffset
+     * @param    integer    $yOffset
+     * @return PHPExcel_Chart
+     */
+    public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
+    {
+        $this->bottomRightCellRef = $cell;
+        if (!is_null($xOffset)) {
+            $this->setBottomRightXOffset($xOffset);
+        }
+        if (!is_null($yOffset)) {
+            $this->setBottomRightYOffset($yOffset);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get the bottom right position of the chart
+     *
+     * @return array    an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+     */
+    public function getBottomRightPosition()
+    {
+        return array(
+            'cell'    => $this->bottomRightCellRef,
+            'xOffset' => $this->bottomRightXOffset,
+            'yOffset' => $this->bottomRightYOffset
+        );
+    }
+
+    public function setBottomRightCell($cell)
+    {
+        $this->bottomRightCellRef = $cell;
+
+        return $this;
+    }
+
+    /**
+     * Get the cell address where the bottom right of the chart is fixed
+     *
+     * @return string
+     */
+    public function getBottomRightCell()
+    {
+        return $this->bottomRightCellRef;
+    }
+
+    /**
+     * Set the offset position within the Bottom Right cell for the chart
+     *
+     * @param    integer    $xOffset
+     * @param    integer    $yOffset
+     * @return PHPExcel_Chart
+     */
+    public function setBottomRightOffset($xOffset = null, $yOffset = null)
+    {
+        if (!is_null($xOffset)) {
+            $this->setBottomRightXOffset($xOffset);
+        }
+        if (!is_null($yOffset)) {
+            $this->setBottomRightYOffset($yOffset);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get the offset position within the Bottom Right cell for the chart
+     *
+     * @return integer[]
+     */
+    public function getBottomRightOffset()
+    {
+        return array(
+            'X' => $this->bottomRightXOffset,
+            'Y' => $this->bottomRightYOffset
+        );
+    }
+
+    public function setBottomRightXOffset($xOffset)
+    {
+        $this->bottomRightXOffset = $xOffset;
+
+        return $this;
+    }
+
+    public function getBottomRightXOffset()
+    {
+        return $this->bottomRightXOffset;
+    }
+
+    public function setBottomRightYOffset($yOffset)
+    {
+        $this->bottomRightYOffset = $yOffset;
+
+        return $this;
+    }
+
+    public function getBottomRightYOffset()
+    {
+        return $this->bottomRightYOffset;
+    }
+
+
+    public function refresh()
+    {
+        if ($this->worksheet !== null) {
+            $this->plotArea->refresh($this->worksheet);
+        }
+    }
+
+    public function render($outputDestination = null)
+    {
+        $libraryName = PHPExcel_Settings::getChartRendererName();
+        if (is_null($libraryName)) {
+            return false;
+        }
+        //    Ensure that data series values are up-to-date before we render
+        $this->refresh();
+
+        $libraryPath = PHPExcel_Settings::getChartRendererPath();
+        $includePath = str_replace('\\', '/', get_include_path());
+        $rendererPath = str_replace('\\', '/', $libraryPath);
+        if (strpos($rendererPath, $includePath) === false) {
+            set_include_path(get_include_path() . PATH_SEPARATOR . $libraryPath);
+        }
+
+        $rendererName = 'PHPExcel_Chart_Renderer_'.$libraryName;
+        $renderer = new $rendererName($this);
+
+        if ($outputDestination == 'php://output') {
+            $outputDestination = null;
+        }
+        return $renderer->render($outputDestination);
+    }
+}

+ 561 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Axis.php

@@ -0,0 +1,561 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: Wiktor Trzonkowski
+ * Date: 6/17/14
+ * Time: 12:11 PM
+ */
+
+class PHPExcel_Chart_Axis extends PHPExcel_Chart_Properties
+{
+    /**
+     * Axis Number
+     *
+     * @var  array of mixed
+     */
+    private $axisNumber = array(
+        'format' => self::FORMAT_CODE_GENERAL,
+        'source_linked' => 1
+    );
+
+    /**
+     * Axis Options
+     *
+     * @var  array of mixed
+     */
+    private $axisOptions = array(
+        'minimum' => null,
+        'maximum' => null,
+        'major_unit' => null,
+        'minor_unit' => null,
+        'orientation' => self::ORIENTATION_NORMAL,
+        'minor_tick_mark' => self::TICK_MARK_NONE,
+        'major_tick_mark' => self::TICK_MARK_NONE,
+        'axis_labels' => self::AXIS_LABELS_NEXT_TO,
+        'horizontal_crosses' => self::HORIZONTAL_CROSSES_AUTOZERO,
+        'horizontal_crosses_value' => null
+    );
+
+    /**
+     * Fill Properties
+     *
+     * @var  array of mixed
+     */
+    private $fillProperties = array(
+        'type' => self::EXCEL_COLOR_TYPE_ARGB,
+        'value' => null,
+        'alpha' => 0
+    );
+
+    /**
+     * Line Properties
+     *
+     * @var  array of mixed
+     */
+    private $lineProperties = array(
+        'type' => self::EXCEL_COLOR_TYPE_ARGB,
+        'value' => null,
+        'alpha' => 0
+    );
+
+    /**
+     * Line Style Properties
+     *
+     * @var  array of mixed
+     */
+    private $lineStyleProperties = array(
+        'width' => '9525',
+        'compound' => self::LINE_STYLE_COMPOUND_SIMPLE,
+        'dash' => self::LINE_STYLE_DASH_SOLID,
+        'cap' => self::LINE_STYLE_CAP_FLAT,
+        'join' => self::LINE_STYLE_JOIN_BEVEL,
+        'arrow' => array(
+            'head' => array(
+                'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+                'size' => self::LINE_STYLE_ARROW_SIZE_5
+            ),
+            'end' => array(
+                'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+                'size' => self::LINE_STYLE_ARROW_SIZE_8
+            ),
+        )
+    );
+
+    /**
+     * Shadow Properties
+     *
+     * @var  array of mixed
+     */
+    private $shadowProperties = array(
+        'presets' => self::SHADOW_PRESETS_NOSHADOW,
+        'effect' => null,
+        'color' => array(
+            'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+            'value' => 'black',
+            'alpha' => 40,
+        ),
+        'size' => array(
+            'sx' => null,
+            'sy' => null,
+            'kx' => null
+        ),
+        'blur' => null,
+        'direction' => null,
+        'distance' => null,
+        'algn' => null,
+        'rotWithShape' => null
+    );
+
+    /**
+     * Glow Properties
+     *
+     * @var  array of mixed
+     */
+    private $glowProperties = array(
+        'size' => null,
+        'color' => array(
+            'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+            'value' => 'black',
+            'alpha' => 40
+        )
+    );
+
+    /**
+     * Soft Edge Properties
+     *
+     * @var  array of mixed
+     */
+    private $softEdges = array(
+        'size' => null
+    );
+
+    /**
+     * Get Series Data Type
+     *
+     * @return  string
+     */
+    public function setAxisNumberProperties($format_code)
+    {
+        $this->axisNumber['format'] = (string) $format_code;
+        $this->axisNumber['source_linked'] = 0;
+    }
+
+    /**
+     * Get Axis Number Format Data Type
+     *
+     * @return  string
+     */
+    public function getAxisNumberFormat()
+    {
+        return $this->axisNumber['format'];
+    }
+
+    /**
+     * Get Axis Number Source Linked
+     *
+     * @return  string
+     */
+    public function getAxisNumberSourceLinked()
+    {
+        return (string) $this->axisNumber['source_linked'];
+    }
+
+    /**
+     * Set Axis Options Properties
+     *
+     * @param string $axis_labels
+     * @param string $horizontal_crosses_value
+     * @param string $horizontal_crosses
+     * @param string $axis_orientation
+     * @param string $major_tmt
+     * @param string $minor_tmt
+     * @param string $minimum
+     * @param string $maximum
+     * @param string $major_unit
+     * @param string $minor_unit
+     *
+     */
+    public function setAxisOptionsProperties($axis_labels, $horizontal_crosses_value = null, $horizontal_crosses = null, $axis_orientation = null, $major_tmt = null, $minor_tmt = null, $minimum = null, $maximum = null, $major_unit = null, $minor_unit = null)
+    {
+        $this->axisOptions['axis_labels'] = (string) $axis_labels;
+        ($horizontal_crosses_value !== null) ? $this->axisOptions['horizontal_crosses_value'] = (string) $horizontal_crosses_value : null;
+        ($horizontal_crosses !== null) ? $this->axisOptions['horizontal_crosses'] = (string) $horizontal_crosses : null;
+        ($axis_orientation !== null) ? $this->axisOptions['orientation'] = (string) $axis_orientation : null;
+        ($major_tmt !== null) ? $this->axisOptions['major_tick_mark'] = (string) $major_tmt : null;
+        ($minor_tmt !== null) ? $this->axisOptions['minor_tick_mark'] = (string) $minor_tmt : null;
+        ($minor_tmt !== null) ? $this->axisOptions['minor_tick_mark'] = (string) $minor_tmt : null;
+        ($minimum !== null) ? $this->axisOptions['minimum'] = (string) $minimum : null;
+        ($maximum !== null) ? $this->axisOptions['maximum'] = (string) $maximum : null;
+        ($major_unit !== null) ? $this->axisOptions['major_unit'] = (string) $major_unit : null;
+        ($minor_unit !== null) ? $this->axisOptions['minor_unit'] = (string) $minor_unit : null;
+    }
+
+    /**
+     * Get Axis Options Property
+     *
+     * @param string $property
+     *
+     * @return string
+     */
+    public function getAxisOptionsProperty($property)
+    {
+        return $this->axisOptions[$property];
+    }
+
+    /**
+     * Set Axis Orientation Property
+     *
+     * @param string $orientation
+     *
+     */
+    public function setAxisOrientation($orientation)
+    {
+        $this->orientation = (string) $orientation;
+    }
+
+    /**
+     * Set Fill Property
+     *
+     * @param string $color
+     * @param int $alpha
+     * @param string $type
+     *
+     */
+    public function setFillParameters($color, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_ARGB)
+    {
+        $this->fillProperties = $this->setColorProperties($color, $alpha, $type);
+    }
+
+    /**
+     * Set Line Property
+     *
+     * @param string $color
+     * @param int $alpha
+     * @param string $type
+     *
+     */
+    public function setLineParameters($color, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_ARGB)
+    {
+        $this->lineProperties = $this->setColorProperties($color, $alpha, $type);
+    }
+
+    /**
+     * Get Fill Property
+     *
+     * @param string $property
+     *
+     * @return string
+     */
+    public function getFillProperty($property)
+    {
+        return $this->fillProperties[$property];
+    }
+
+    /**
+     * Get Line Property
+     *
+     * @param string $property
+     *
+     * @return string
+     */
+    public function getLineProperty($property)
+    {
+        return $this->lineProperties[$property];
+    }
+
+    /**
+     * Set Line Style Properties
+     *
+     * @param float $line_width
+     * @param string $compound_type
+     * @param string $dash_type
+     * @param string $cap_type
+     * @param string $join_type
+     * @param string $head_arrow_type
+     * @param string $head_arrow_size
+     * @param string $end_arrow_type
+     * @param string $end_arrow_size
+     *
+     */
+    public function setLineStyleProperties($line_width = null, $compound_type = null, $dash_type = null, $cap_type = null, $join_type = null, $head_arrow_type = null, $head_arrow_size = null, $end_arrow_type = null, $end_arrow_size = null)
+    {
+        (!is_null($line_width)) ? $this->lineStyleProperties['width'] = $this->getExcelPointsWidth((float) $line_width) : null;
+        (!is_null($compound_type)) ? $this->lineStyleProperties['compound'] = (string) $compound_type : null;
+        (!is_null($dash_type)) ? $this->lineStyleProperties['dash'] = (string) $dash_type : null;
+        (!is_null($cap_type)) ? $this->lineStyleProperties['cap'] = (string) $cap_type : null;
+        (!is_null($join_type)) ? $this->lineStyleProperties['join'] = (string) $join_type : null;
+        (!is_null($head_arrow_type)) ? $this->lineStyleProperties['arrow']['head']['type'] = (string) $head_arrow_type : null;
+        (!is_null($head_arrow_size)) ? $this->lineStyleProperties['arrow']['head']['size'] = (string) $head_arrow_size : null;
+        (!is_null($end_arrow_type)) ? $this->lineStyleProperties['arrow']['end']['type'] = (string) $end_arrow_type : null;
+        (!is_null($end_arrow_size)) ? $this->lineStyleProperties['arrow']['end']['size'] = (string) $end_arrow_size : null;
+    }
+
+    /**
+     * Get Line Style Property
+     *
+     * @param array|string $elements
+     *
+     * @return string
+     */
+    public function getLineStyleProperty($elements)
+    {
+        return $this->getArrayElementsValue($this->lineStyleProperties, $elements);
+    }
+
+    /**
+     * Get Line Style Arrow Excel Width
+     *
+     * @param string $arrow
+     *
+     * @return string
+     */
+    public function getLineStyleArrowWidth($arrow)
+    {
+        return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'w');
+    }
+
+    /**
+     * Get Line Style Arrow Excel Length
+     *
+     * @param string $arrow
+     *
+     * @return string
+     */
+    public function getLineStyleArrowLength($arrow)
+    {
+        return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'len');
+    }
+
+    /**
+     * Set Shadow Properties
+     *
+     * @param int $shadow_presets
+     * @param string $sh_color_value
+     * @param string $sh_color_type
+     * @param string $sh_color_alpha
+     * @param float $sh_blur
+     * @param int $sh_angle
+     * @param float $sh_distance
+     *
+     */
+    public function setShadowProperties($sh_presets, $sh_color_value = null, $sh_color_type = null, $sh_color_alpha = null, $sh_blur = null, $sh_angle = null, $sh_distance = null)
+    {
+        $this->setShadowPresetsProperties((int) $sh_presets)
+            ->setShadowColor(
+                is_null($sh_color_value) ? $this->shadowProperties['color']['value'] : $sh_color_value,
+                is_null($sh_color_alpha) ? (int) $this->shadowProperties['color']['alpha'] : $sh_color_alpha,
+                is_null($sh_color_type) ? $this->shadowProperties['color']['type'] : $sh_color_type
+            )
+            ->setShadowBlur($sh_blur)
+            ->setShadowAngle($sh_angle)
+            ->setShadowDistance($sh_distance);
+    }
+
+    /**
+     * Set Shadow Color
+     *
+     * @param int $shadow_presets
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setShadowPresetsProperties($shadow_presets)
+    {
+        $this->shadowProperties['presets'] = $shadow_presets;
+        $this->setShadowProperiesMapValues($this->getShadowPresetsMap($shadow_presets));
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Properties from Maped Values
+     *
+     * @param array $properties_map
+     * @param * $reference
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
+    {
+        $base_reference = $reference;
+        foreach ($properties_map as $property_key => $property_val) {
+            if (is_array($property_val)) {
+                if ($reference === null) {
+                    $reference = & $this->shadowProperties[$property_key];
+                } else {
+                    $reference = & $reference[$property_key];
+                }
+                $this->setShadowProperiesMapValues($property_val, $reference);
+            } else {
+                if ($base_reference === null) {
+                    $this->shadowProperties[$property_key] = $property_val;
+                } else {
+                    $reference[$property_key] = $property_val;
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Color
+     *
+     * @param string $color
+     * @param int $alpha
+     * @param string $type
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setShadowColor($color, $alpha, $type)
+    {
+        $this->shadowProperties['color'] = $this->setColorProperties($color, $alpha, $type);
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Blur
+     *
+     * @param float $blur
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setShadowBlur($blur)
+    {
+        if ($blur !== null) {
+            $this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Angle
+     *
+     * @param int $angle
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setShadowAngle($angle)
+    {
+        if ($angle !== null) {
+            $this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Distance
+     *
+     * @param float $distance
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setShadowDistance($distance)
+    {
+        if ($distance !== null) {
+            $this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get Glow Property
+     *
+     * @param float $size
+     * @param string $color_value
+     * @param int $color_alpha
+     * @param string $color_type
+     */
+    public function getShadowProperty($elements)
+    {
+        return $this->getArrayElementsValue($this->shadowProperties, $elements);
+    }
+
+    /**
+     * Set Glow Properties
+     *
+     * @param float $size
+     * @param string $color_value
+     * @param int $color_alpha
+     * @param string $color_type
+     */
+    public function setGlowProperties($size, $color_value = null, $color_alpha = null, $color_type = null)
+    {
+        $this->setGlowSize($size)
+            ->setGlowColor(
+                is_null($color_value) ? $this->glowProperties['color']['value'] : $color_value,
+                is_null($color_alpha) ? (int) $this->glowProperties['color']['alpha'] : $color_alpha,
+                is_null($color_type) ? $this->glowProperties['color']['type'] : $color_type
+            );
+    }
+
+    /**
+     * Get Glow Property
+     *
+     * @param array|string $property
+     *
+     * @return string
+     */
+    public function getGlowProperty($property)
+    {
+        return $this->getArrayElementsValue($this->glowProperties, $property);
+    }
+
+    /**
+     * Set Glow Color
+     *
+     * @param float $size
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setGlowSize($size)
+    {
+        if (!is_null($size)) {
+            $this->glowProperties['size'] = $this->getExcelPointsWidth($size);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Glow Color
+     *
+     * @param string $color
+     * @param int $alpha
+     * @param string $type
+     *
+     * @return PHPExcel_Chart_Axis
+     */
+    private function setGlowColor($color, $alpha, $type)
+    {
+        $this->glowProperties['color'] = $this->setColorProperties($color, $alpha, $type);
+
+        return $this;
+    }
+
+    /**
+     * Set Soft Edges Size
+     *
+     * @param float $size
+     */
+    public function setSoftEdges($size)
+    {
+        if (!is_null($size)) {
+            $softEdges['size'] = (string) $this->getExcelPointsWidth($size);
+        }
+    }
+
+    /**
+     * Get Soft Edges Size
+     *
+     * @return string
+     */
+    public function getSoftEdgesSize()
+    {
+        return $this->softEdges['size'];
+    }
+}

+ 390 - 0
backend/RTP/extend/excel/PHPExcel/Chart/DataSeries.php

@@ -0,0 +1,390 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+
+
+/**
+ * PHPExcel_Chart_DataSeries
+ *
+ * @category    PHPExcel
+ * @package        PHPExcel_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_DataSeries
+{
+    const TYPE_BARCHART        = 'barChart';
+    const TYPE_BARCHART_3D     = 'bar3DChart';
+    const TYPE_LINECHART       = 'lineChart';
+    const TYPE_LINECHART_3D    = 'line3DChart';
+    const TYPE_AREACHART       = 'areaChart';
+    const TYPE_AREACHART_3D    = 'area3DChart';
+    const TYPE_PIECHART        = 'pieChart';
+    const TYPE_PIECHART_3D     = 'pie3DChart';
+    const TYPE_DOUGHTNUTCHART  = 'doughnutChart';
+    const TYPE_DONUTCHART      = self::TYPE_DOUGHTNUTCHART;    //    Synonym
+    const TYPE_SCATTERCHART    = 'scatterChart';
+    const TYPE_SURFACECHART    = 'surfaceChart';
+    const TYPE_SURFACECHART_3D = 'surface3DChart';
+    const TYPE_RADARCHART      = 'radarChart';
+    const TYPE_BUBBLECHART     = 'bubbleChart';
+    const TYPE_STOCKCHART      = 'stockChart';
+    const TYPE_CANDLECHART     = self::TYPE_STOCKCHART;       //    Synonym
+
+    const GROUPING_CLUSTERED       = 'clustered';
+    const GROUPING_STACKED         = 'stacked';
+    const GROUPING_PERCENT_STACKED = 'percentStacked';
+    const GROUPING_STANDARD        = 'standard';
+
+    const DIRECTION_BAR        = 'bar';
+    const DIRECTION_HORIZONTAL = self::DIRECTION_BAR;
+    const DIRECTION_COL        = 'col';
+    const DIRECTION_COLUMN     = self::DIRECTION_COL;
+    const DIRECTION_VERTICAL   = self::DIRECTION_COL;
+
+    const STYLE_LINEMARKER   = 'lineMarker';
+    const STYLE_SMOOTHMARKER = 'smoothMarker';
+    const STYLE_MARKER       = 'marker';
+    const STYLE_FILLED       = 'filled';
+
+
+    /**
+     * Series Plot Type
+     *
+     * @var string
+     */
+    private $plotType;
+
+    /**
+     * Plot Grouping Type
+     *
+     * @var boolean
+     */
+    private $plotGrouping;
+
+    /**
+     * Plot Direction
+     *
+     * @var boolean
+     */
+    private $plotDirection;
+
+    /**
+     * Plot Style
+     *
+     * @var string
+     */
+    private $plotStyle;
+
+    /**
+     * Order of plots in Series
+     *
+     * @var array of integer
+     */
+    private $plotOrder = array();
+
+    /**
+     * Plot Label
+     *
+     * @var array of PHPExcel_Chart_DataSeriesValues
+     */
+    private $plotLabel = array();
+
+    /**
+     * Plot Category
+     *
+     * @var array of PHPExcel_Chart_DataSeriesValues
+     */
+    private $plotCategory = array();
+
+    /**
+     * Smooth Line
+     *
+     * @var string
+     */
+    private $smoothLine;
+
+    /**
+     * Plot Values
+     *
+     * @var array of PHPExcel_Chart_DataSeriesValues
+     */
+    private $plotValues = array();
+
+    /**
+     * Create a new PHPExcel_Chart_DataSeries
+     */
+    public function __construct($plotType = null, $plotGrouping = null, $plotOrder = array(), $plotLabel = array(), $plotCategory = array(), $plotValues = array(), $plotDirection = null, $smoothLine = null, $plotStyle = null)
+    {
+        $this->plotType = $plotType;
+        $this->plotGrouping = $plotGrouping;
+        $this->plotOrder = $plotOrder;
+        $keys = array_keys($plotValues);
+        $this->plotValues = $plotValues;
+        if ((count($plotLabel) == 0) || (is_null($plotLabel[$keys[0]]))) {
+            $plotLabel[$keys[0]] = new PHPExcel_Chart_DataSeriesValues();
+        }
+
+        $this->plotLabel = $plotLabel;
+        if ((count($plotCategory) == 0) || (is_null($plotCategory[$keys[0]]))) {
+            $plotCategory[$keys[0]] = new PHPExcel_Chart_DataSeriesValues();
+        }
+        $this->plotCategory = $plotCategory;
+        $this->smoothLine = $smoothLine;
+        $this->plotStyle = $plotStyle;
+        
+        if (is_null($plotDirection)) {
+            $plotDirection = self::DIRECTION_COL;
+        }
+        $this->plotDirection = $plotDirection;
+    }
+
+    /**
+     * Get Plot Type
+     *
+     * @return string
+     */
+    public function getPlotType()
+    {
+        return $this->plotType;
+    }
+
+    /**
+     * Set Plot Type
+     *
+     * @param string $plotType
+     * @return PHPExcel_Chart_DataSeries
+     */
+    public function setPlotType($plotType = '')
+    {
+        $this->plotType = $plotType;
+        return $this;
+    }
+
+    /**
+     * Get Plot Grouping Type
+     *
+     * @return string
+     */
+    public function getPlotGrouping()
+    {
+        return $this->plotGrouping;
+    }
+
+    /**
+     * Set Plot Grouping Type
+     *
+     * @param string $groupingType
+     * @return PHPExcel_Chart_DataSeries
+     */
+    public function setPlotGrouping($groupingType = null)
+    {
+        $this->plotGrouping = $groupingType;
+        return $this;
+    }
+
+    /**
+     * Get Plot Direction
+     *
+     * @return string
+     */
+    public function getPlotDirection()
+    {
+        return $this->plotDirection;
+    }
+
+    /**
+     * Set Plot Direction
+     *
+     * @param string $plotDirection
+     * @return PHPExcel_Chart_DataSeries
+     */
+    public function setPlotDirection($plotDirection = null)
+    {
+        $this->plotDirection = $plotDirection;
+        return $this;
+    }
+
+    /**
+     * Get Plot Order
+     *
+     * @return string
+     */
+    public function getPlotOrder()
+    {
+        return $this->plotOrder;
+    }
+
+    /**
+     * Get Plot Labels
+     *
+     * @return array of PHPExcel_Chart_DataSeriesValues
+     */
+    public function getPlotLabels()
+    {
+        return $this->plotLabel;
+    }
+
+    /**
+     * Get Plot Label by Index
+     *
+     * @return PHPExcel_Chart_DataSeriesValues
+     */
+    public function getPlotLabelByIndex($index)
+    {
+        $keys = array_keys($this->plotLabel);
+        if (in_array($index, $keys)) {
+            return $this->plotLabel[$index];
+        } elseif (isset($keys[$index])) {
+            return $this->plotLabel[$keys[$index]];
+        }
+        return false;
+    }
+
+    /**
+     * Get Plot Categories
+     *
+     * @return array of PHPExcel_Chart_DataSeriesValues
+     */
+    public function getPlotCategories()
+    {
+        return $this->plotCategory;
+    }
+
+    /**
+     * Get Plot Category by Index
+     *
+     * @return PHPExcel_Chart_DataSeriesValues
+     */
+    public function getPlotCategoryByIndex($index)
+    {
+        $keys = array_keys($this->plotCategory);
+        if (in_array($index, $keys)) {
+            return $this->plotCategory[$index];
+        } elseif (isset($keys[$index])) {
+            return $this->plotCategory[$keys[$index]];
+        }
+        return false;
+    }
+
+    /**
+     * Get Plot Style
+     *
+     * @return string
+     */
+    public function getPlotStyle()
+    {
+        return $this->plotStyle;
+    }
+
+    /**
+     * Set Plot Style
+     *
+     * @param string $plotStyle
+     * @return PHPExcel_Chart_DataSeries
+     */
+    public function setPlotStyle($plotStyle = null)
+    {
+        $this->plotStyle = $plotStyle;
+        return $this;
+    }
+
+    /**
+     * Get Plot Values
+     *
+     * @return array of PHPExcel_Chart_DataSeriesValues
+     */
+    public function getPlotValues()
+    {
+        return $this->plotValues;
+    }
+
+    /**
+     * Get Plot Values by Index
+     *
+     * @return PHPExcel_Chart_DataSeriesValues
+     */
+    public function getPlotValuesByIndex($index)
+    {
+        $keys = array_keys($this->plotValues);
+        if (in_array($index, $keys)) {
+            return $this->plotValues[$index];
+        } elseif (isset($keys[$index])) {
+            return $this->plotValues[$keys[$index]];
+        }
+        return false;
+    }
+
+    /**
+     * Get Number of Plot Series
+     *
+     * @return integer
+     */
+    public function getPlotSeriesCount()
+    {
+        return count($this->plotValues);
+    }
+
+    /**
+     * Get Smooth Line
+     *
+     * @return boolean
+     */
+    public function getSmoothLine()
+    {
+        return $this->smoothLine;
+    }
+
+    /**
+     * Set Smooth Line
+     *
+     * @param boolean $smoothLine
+     * @return PHPExcel_Chart_DataSeries
+     */
+    public function setSmoothLine($smoothLine = true)
+    {
+        $this->smoothLine = $smoothLine;
+        return $this;
+    }
+
+    public function refresh(PHPExcel_Worksheet $worksheet)
+    {
+        foreach ($this->plotValues as $plotValues) {
+            if ($plotValues !== null) {
+                $plotValues->refresh($worksheet, true);
+            }
+        }
+        foreach ($this->plotLabel as $plotValues) {
+            if ($plotValues !== null) {
+                $plotValues->refresh($worksheet, true);
+            }
+        }
+        foreach ($this->plotCategory as $plotValues) {
+            if ($plotValues !== null) {
+                $plotValues->refresh($worksheet, false);
+            }
+        }
+    }
+}

+ 333 - 0
backend/RTP/extend/excel/PHPExcel/Chart/DataSeriesValues.php

@@ -0,0 +1,333 @@
+<?php
+
+/**
+ * PHPExcel_Chart_DataSeriesValues
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Chart_DataSeriesValues
+{
+
+    const DATASERIES_TYPE_STRING    = 'String';
+    const DATASERIES_TYPE_NUMBER    = 'Number';
+
+    private static $dataTypeValues = array(
+        self::DATASERIES_TYPE_STRING,
+        self::DATASERIES_TYPE_NUMBER,
+    );
+
+    /**
+     * Series Data Type
+     *
+     * @var    string
+     */
+    private $dataType;
+
+    /**
+     * Series Data Source
+     *
+     * @var    string
+     */
+    private $dataSource;
+
+    /**
+     * Format Code
+     *
+     * @var    string
+     */
+    private $formatCode;
+
+    /**
+     * Series Point Marker
+     *
+     * @var    string
+     */
+    private $pointMarker;
+
+    /**
+     * Point Count (The number of datapoints in the dataseries)
+     *
+     * @var    integer
+     */
+    private $pointCount = 0;
+
+    /**
+     * Data Values
+     *
+     * @var    array of mixed
+     */
+    private $dataValues = array();
+
+    /**
+     * Create a new PHPExcel_Chart_DataSeriesValues object
+     */
+    public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = array(), $marker = null)
+    {
+        $this->setDataType($dataType);
+        $this->dataSource = $dataSource;
+        $this->formatCode = $formatCode;
+        $this->pointCount = $pointCount;
+        $this->dataValues = $dataValues;
+        $this->pointMarker = $marker;
+    }
+
+    /**
+     * Get Series Data Type
+     *
+     * @return    string
+     */
+    public function getDataType()
+    {
+        return $this->dataType;
+    }
+
+    /**
+     * Set Series Data Type
+     *
+     * @param    string    $dataType    Datatype of this data series
+     *                                Typical values are:
+     *                                    PHPExcel_Chart_DataSeriesValues::DATASERIES_TYPE_STRING
+     *                                        Normally used for axis point values
+     *                                    PHPExcel_Chart_DataSeriesValues::DATASERIES_TYPE_NUMBER
+     *                                        Normally used for chart data values
+     * @return    PHPExcel_Chart_DataSeriesValues
+     */
+    public function setDataType($dataType = self::DATASERIES_TYPE_NUMBER)
+    {
+        if (!in_array($dataType, self::$dataTypeValues)) {
+            throw new PHPExcel_Chart_Exception('Invalid datatype for chart data series values');
+        }
+        $this->dataType = $dataType;
+
+        return $this;
+    }
+
+    /**
+     * Get Series Data Source (formula)
+     *
+     * @return    string
+     */
+    public function getDataSource()
+    {
+        return $this->dataSource;
+    }
+
+    /**
+     * Set Series Data Source (formula)
+     *
+     * @param    string    $dataSource
+     * @return    PHPExcel_Chart_DataSeriesValues
+     */
+    public function setDataSource($dataSource = null, $refreshDataValues = true)
+    {
+        $this->dataSource = $dataSource;
+
+        if ($refreshDataValues) {
+            //    TO DO
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get Point Marker
+     *
+     * @return string
+     */
+    public function getPointMarker()
+    {
+        return $this->pointMarker;
+    }
+
+    /**
+     * Set Point Marker
+     *
+     * @param    string    $marker
+     * @return    PHPExcel_Chart_DataSeriesValues
+     */
+    public function setPointMarker($marker = null)
+    {
+        $this->pointMarker = $marker;
+
+        return $this;
+    }
+
+    /**
+     * Get Series Format Code
+     *
+     * @return    string
+     */
+    public function getFormatCode()
+    {
+        return $this->formatCode;
+    }
+
+    /**
+     * Set Series Format Code
+     *
+     * @param    string    $formatCode
+     * @return    PHPExcel_Chart_DataSeriesValues
+     */
+    public function setFormatCode($formatCode = null)
+    {
+        $this->formatCode = $formatCode;
+
+        return $this;
+    }
+
+    /**
+     * Get Series Point Count
+     *
+     * @return    integer
+     */
+    public function getPointCount()
+    {
+        return $this->pointCount;
+    }
+
+    /**
+     * Identify if the Data Series is a multi-level or a simple series
+     *
+     * @return    boolean
+     */
+    public function isMultiLevelSeries()
+    {
+        if (count($this->dataValues) > 0) {
+            return is_array($this->dataValues[0]);
+        }
+        return null;
+    }
+
+    /**
+     * Return the level count of a multi-level Data Series
+     *
+     * @return    boolean
+     */
+    public function multiLevelCount()
+    {
+        $levelCount = 0;
+        foreach ($this->dataValues as $dataValueSet) {
+            $levelCount = max($levelCount, count($dataValueSet));
+        }
+        return $levelCount;
+    }
+
+    /**
+     * Get Series Data Values
+     *
+     * @return    array of mixed
+     */
+    public function getDataValues()
+    {
+        return $this->dataValues;
+    }
+
+    /**
+     * Get the first Series Data value
+     *
+     * @return    mixed
+     */
+    public function getDataValue()
+    {
+        $count = count($this->dataValues);
+        if ($count == 0) {
+            return null;
+        } elseif ($count == 1) {
+            return $this->dataValues[0];
+        }
+        return $this->dataValues;
+    }
+
+    /**
+     * Set Series Data Values
+     *
+     * @param    array    $dataValues
+     * @param    boolean    $refreshDataSource
+     *                    TRUE - refresh the value of dataSource based on the values of $dataValues
+     *                    FALSE - don't change the value of dataSource
+     * @return    PHPExcel_Chart_DataSeriesValues
+     */
+    public function setDataValues($dataValues = array(), $refreshDataSource = true)
+    {
+        $this->dataValues = PHPExcel_Calculation_Functions::flattenArray($dataValues);
+        $this->pointCount = count($dataValues);
+
+        if ($refreshDataSource) {
+            //    TO DO
+        }
+
+        return $this;
+    }
+
+    private function stripNulls($var)
+    {
+        return $var !== null;
+    }
+
+    public function refresh(PHPExcel_Worksheet $worksheet, $flatten = true)
+    {
+        if ($this->dataSource !== null) {
+            $calcEngine = PHPExcel_Calculation::getInstance($worksheet->getParent());
+            $newDataValues = PHPExcel_Calculation::unwrapResult(
+                $calcEngine->_calculateFormulaValue(
+                    '='.$this->dataSource,
+                    null,
+                    $worksheet->getCell('A1')
+                )
+            );
+            if ($flatten) {
+                $this->dataValues = PHPExcel_Calculation_Functions::flattenArray($newDataValues);
+                foreach ($this->dataValues as &$dataValue) {
+                    if ((!empty($dataValue)) && ($dataValue[0] == '#')) {
+                        $dataValue = 0.0;
+                    }
+                }
+                unset($dataValue);
+            } else {
+                $cellRange = explode('!', $this->dataSource);
+                if (count($cellRange) > 1) {
+                    list(, $cellRange) = $cellRange;
+                }
+
+                $dimensions = PHPExcel_Cell::rangeDimension(str_replace('$', '', $cellRange));
+                if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
+                    $this->dataValues = PHPExcel_Calculation_Functions::flattenArray($newDataValues);
+                } else {
+                    $newArray = array_values(array_shift($newDataValues));
+                    foreach ($newArray as $i => $newDataSet) {
+                        $newArray[$i] = array($newDataSet);
+                    }
+
+                    foreach ($newDataValues as $newDataSet) {
+                        $i = 0;
+                        foreach ($newDataSet as $newDataVal) {
+                            array_unshift($newArray[$i++], $newDataVal);
+                        }
+                    }
+                    $this->dataValues = $newArray;
+                }
+            }
+            $this->pointCount = count($this->dataValues);
+        }
+    }
+}

+ 46 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Exception.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * PHPExcel_Chart_Exception
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Chart_Exception extends PHPExcel_Exception
+{
+    /**
+     * Error handler callback
+     *
+     * @param mixed $code
+     * @param mixed $string
+     * @param mixed $file
+     * @param mixed $line
+     * @param mixed $context
+     */
+    public static function errorHandlerCallback($code, $string, $file, $line, $context)
+    {
+        $e = new self($string, $code);
+        $e->line = $line;
+        $e->file = $file;
+        throw $e;
+    }
+}

+ 472 - 0
backend/RTP/extend/excel/PHPExcel/Chart/GridLines.php

@@ -0,0 +1,472 @@
+<?php
+
+/**
+ * Created by PhpStorm.
+ * User: Wiktor Trzonkowski
+ * Date: 7/2/14
+ * Time: 2:36 PM
+ */
+
+class PHPExcel_Chart_GridLines extends PHPExcel_Chart_Properties
+{
+
+  /**
+   * Properties of Class:
+   * Object State (State for Minor Tick Mark) @var bool
+   * Line Properties @var  array of mixed
+   * Shadow Properties @var  array of mixed
+   * Glow Properties @var  array of mixed
+   * Soft Properties @var  array of mixed
+   *
+   */
+
+    private $objectState = false;
+
+    private $lineProperties = array(
+        'color' => array(
+            'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+            'value' => null,
+            'alpha' => 0
+        ),
+        'style' => array(
+            'width' => '9525',
+            'compound' => self::LINE_STYLE_COMPOUND_SIMPLE,
+            'dash' => self::LINE_STYLE_DASH_SOLID,
+            'cap' => self::LINE_STYLE_CAP_FLAT,
+            'join' => self::LINE_STYLE_JOIN_BEVEL,
+            'arrow' => array(
+                'head' => array(
+                    'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+                    'size' => self::LINE_STYLE_ARROW_SIZE_5
+                ),
+                'end' => array(
+                    'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+                    'size' => self::LINE_STYLE_ARROW_SIZE_8
+                ),
+            )
+        )
+    );
+
+    private $shadowProperties = array(
+        'presets' => self::SHADOW_PRESETS_NOSHADOW,
+        'effect' => null,
+        'color' => array(
+            'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+            'value' => 'black',
+            'alpha' => 85,
+        ),
+        'size' => array(
+            'sx' => null,
+            'sy' => null,
+            'kx' => null
+        ),
+        'blur' => null,
+        'direction' => null,
+        'distance' => null,
+        'algn' => null,
+        'rotWithShape' => null
+    );
+
+    private $glowProperties = array(
+        'size' => null,
+        'color' => array(
+            'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+            'value' => 'black',
+            'alpha' => 40
+        )
+    );
+
+    private $softEdges = array(
+        'size' => null
+     );
+
+    /**
+     * Get Object State
+     *
+     * @return bool
+     */
+
+    public function getObjectState()
+    {
+        return $this->objectState;
+    }
+
+    /**
+     * Change Object State to True
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+
+    private function activateObject()
+    {
+        $this->objectState = true;
+
+        return $this;
+    }
+
+    /**
+     * Set Line Color Properties
+     *
+     * @param string $value
+     * @param int $alpha
+     * @param string $type
+     */
+
+    public function setLineColorProperties($value, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_STANDARD)
+    {
+        $this->activateObject()
+            ->lineProperties['color'] = $this->setColorProperties(
+                $value,
+                $alpha,
+                $type
+            );
+    }
+
+    /**
+     * Set Line Color Properties
+     *
+     * @param float $line_width
+     * @param string $compound_type
+     * @param string $dash_type
+     * @param string $cap_type
+     * @param string $join_type
+     * @param string $head_arrow_type
+     * @param string $head_arrow_size
+     * @param string $end_arrow_type
+     * @param string $end_arrow_size
+     */
+
+    public function setLineStyleProperties($line_width = null, $compound_type = null, $dash_type = null, $cap_type = null, $join_type = null, $head_arrow_type = null, $head_arrow_size = null, $end_arrow_type = null, $end_arrow_size = null)
+    {
+        $this->activateObject();
+        (!is_null($line_width))
+                ? $this->lineProperties['style']['width'] = $this->getExcelPointsWidth((float) $line_width)
+                : null;
+        (!is_null($compound_type))
+                ? $this->lineProperties['style']['compound'] = (string) $compound_type
+                : null;
+        (!is_null($dash_type))
+                ? $this->lineProperties['style']['dash'] = (string) $dash_type
+                : null;
+        (!is_null($cap_type))
+                ? $this->lineProperties['style']['cap'] = (string) $cap_type
+                : null;
+        (!is_null($join_type))
+                ? $this->lineProperties['style']['join'] = (string) $join_type
+                : null;
+        (!is_null($head_arrow_type))
+                ? $this->lineProperties['style']['arrow']['head']['type'] = (string) $head_arrow_type
+                : null;
+        (!is_null($head_arrow_size))
+                ? $this->lineProperties['style']['arrow']['head']['size'] = (string) $head_arrow_size
+                : null;
+        (!is_null($end_arrow_type))
+                ? $this->lineProperties['style']['arrow']['end']['type'] = (string) $end_arrow_type
+                : null;
+        (!is_null($end_arrow_size))
+                ? $this->lineProperties['style']['arrow']['end']['size'] = (string) $end_arrow_size
+                : null;
+    }
+
+    /**
+     * Get Line Color Property
+     *
+     * @param string $parameter
+     *
+     * @return string
+     */
+
+    public function getLineColorProperty($parameter)
+    {
+        return $this->lineProperties['color'][$parameter];
+    }
+
+    /**
+     * Get Line Style Property
+     *
+     * @param    array|string $elements
+     *
+     * @return string
+     */
+
+    public function getLineStyleProperty($elements)
+    {
+        return $this->getArrayElementsValue($this->lineProperties['style'], $elements);
+    }
+
+    /**
+     * Set Glow Properties
+     *
+     * @param    float $size
+     * @param    string $color_value
+     * @param    int $color_alpha
+     * @param    string $color_type
+     *
+     */
+
+    public function setGlowProperties($size, $color_value = null, $color_alpha = null, $color_type = null)
+    {
+        $this
+                ->activateObject()
+                ->setGlowSize($size)
+                ->setGlowColor($color_value, $color_alpha, $color_type);
+    }
+
+    /**
+     * Get Glow Color Property
+     *
+     * @param string $property
+     *
+     * @return string
+     */
+
+    public function getGlowColor($property)
+    {
+        return $this->glowProperties['color'][$property];
+    }
+
+    /**
+     * Get Glow Size
+     *
+     * @return string
+     */
+
+    public function getGlowSize()
+    {
+        return $this->glowProperties['size'];
+    }
+
+    /**
+     * Set Glow Size
+     *
+     * @param float $size
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+
+    private function setGlowSize($size)
+    {
+        $this->glowProperties['size'] = $this->getExcelPointsWidth((float) $size);
+
+        return $this;
+    }
+
+    /**
+     * Set Glow Color
+     *
+     * @param string $color
+     * @param int $alpha
+     * @param string $type
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+
+    private function setGlowColor($color, $alpha, $type)
+    {
+        if (!is_null($color)) {
+            $this->glowProperties['color']['value'] = (string) $color;
+        }
+        if (!is_null($alpha)) {
+            $this->glowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha);
+        }
+        if (!is_null($type)) {
+            $this->glowProperties['color']['type'] = (string) $type;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get Line Style Arrow Parameters
+     *
+     * @param string $arrow_selector
+     * @param string $property_selector
+     *
+     * @return string
+     */
+
+    public function getLineStyleArrowParameters($arrow_selector, $property_selector)
+    {
+        return $this->getLineStyleArrowSize($this->lineProperties['style']['arrow'][$arrow_selector]['size'], $property_selector);
+    }
+
+    /**
+     * Set Shadow Properties
+     *
+     * @param int $sh_presets
+     * @param string $sh_color_value
+     * @param string $sh_color_type
+     * @param int $sh_color_alpha
+     * @param string $sh_blur
+     * @param int $sh_angle
+     * @param float $sh_distance
+     *
+     */
+
+    public function setShadowProperties($sh_presets, $sh_color_value = null, $sh_color_type = null, $sh_color_alpha = null, $sh_blur = null, $sh_angle = null, $sh_distance = null)
+    {
+        $this->activateObject()
+            ->setShadowPresetsProperties((int) $sh_presets)
+            ->setShadowColor(
+                is_null($sh_color_value) ? $this->shadowProperties['color']['value'] : $sh_color_value,
+                is_null($sh_color_alpha) ? (int) $this->shadowProperties['color']['alpha'] : $this->getTrueAlpha($sh_color_alpha),
+                is_null($sh_color_type) ? $this->shadowProperties['color']['type'] : $sh_color_type
+            )
+            ->setShadowBlur($sh_blur)
+            ->setShadowAngle($sh_angle)
+            ->setShadowDistance($sh_distance);
+    }
+
+    /**
+     * Set Shadow Presets Properties
+     *
+     * @param int $shadow_presets
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+
+    private function setShadowPresetsProperties($shadow_presets)
+    {
+        $this->shadowProperties['presets'] = $shadow_presets;
+        $this->setShadowProperiesMapValues($this->getShadowPresetsMap($shadow_presets));
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Properties Values
+     *
+     * @param array $properties_map
+     * @param * $reference
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+
+    private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
+    {
+        $base_reference = $reference;
+        foreach ($properties_map as $property_key => $property_val) {
+            if (is_array($property_val)) {
+                if ($reference === null) {
+                    $reference = & $this->shadowProperties[$property_key];
+                } else {
+                    $reference = & $reference[$property_key];
+                }
+                $this->setShadowProperiesMapValues($property_val, $reference);
+            } else {
+                if ($base_reference === null) {
+                    $this->shadowProperties[$property_key] = $property_val;
+                } else {
+                    $reference[$property_key] = $property_val;
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Color
+     *
+     * @param string $color
+     * @param int $alpha
+     * @param string $type
+     * @return PHPExcel_Chart_GridLines
+     */
+    private function setShadowColor($color, $alpha, $type)
+    {
+        if (!is_null($color)) {
+            $this->shadowProperties['color']['value'] = (string) $color;
+        }
+        if (!is_null($alpha)) {
+            $this->shadowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha);
+        }
+        if (!is_null($type)) {
+            $this->shadowProperties['color']['type'] = (string) $type;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Blur
+     *
+     * @param float $blur
+     *
+     * @return PHPExcel_Chart_GridLines
+     */
+    private function setShadowBlur($blur)
+    {
+        if ($blur !== null) {
+            $this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Angle
+     *
+     * @param int $angle
+     * @return PHPExcel_Chart_GridLines
+     */
+
+    private function setShadowAngle($angle)
+    {
+        if ($angle !== null) {
+            $this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set Shadow Distance
+     *
+     * @param float $distance
+     * @return PHPExcel_Chart_GridLines
+     */
+    private function setShadowDistance($distance)
+    {
+        if ($distance !== null) {
+            $this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get Shadow Property
+     *
+     * @param string $elements
+     * @param array $elements
+     * @return string
+     */
+    public function getShadowProperty($elements)
+    {
+        return $this->getArrayElementsValue($this->shadowProperties, $elements);
+    }
+
+    /**
+     * Set Soft Edges Size
+     *
+     * @param float $size
+     */
+    public function setSoftEdgesSize($size)
+    {
+        if (!is_null($size)) {
+            $this->activateObject();
+            $softEdges['size'] = (string) $this->getExcelPointsWidth($size);
+        }
+    }
+
+    /**
+     * Get Soft Edges Size
+     *
+     * @return string
+     */
+    public function getSoftEdgesSize()
+    {
+        return $this->softEdges['size'];
+    }
+}

+ 486 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Layout.php

@@ -0,0 +1,486 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+
+
+/**
+ * PHPExcel_Chart_Layout
+ *
+ * @category    PHPExcel
+ * @package        PHPExcel_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_Layout
+{
+    /**
+     * layoutTarget
+     *
+     * @var string
+     */
+    private $layoutTarget;
+
+    /**
+     * X Mode
+     *
+     * @var string
+     */
+    private $xMode;
+
+    /**
+     * Y Mode
+     *
+     * @var string
+     */
+    private $yMode;
+
+    /**
+     * X-Position
+     *
+     * @var float
+     */
+    private $xPos;
+
+    /**
+     * Y-Position
+     *
+     * @var float
+     */
+    private $yPos;
+
+    /**
+     * width
+     *
+     * @var float
+     */
+    private $width;
+
+    /**
+     * height
+     *
+     * @var float
+     */
+    private $height;
+
+    /**
+     * show legend key
+     * Specifies that legend keys should be shown in data labels
+     *
+     * @var boolean
+     */
+    private $showLegendKey;
+
+    /**
+     * show value
+     * Specifies that the value should be shown in a data label.
+     *
+     * @var boolean
+     */
+    private $showVal;
+
+    /**
+     * show category name
+     * Specifies that the category name should be shown in the data label.
+     *
+     * @var boolean
+     */
+    private $showCatName;
+
+    /**
+     * show data series name
+     * Specifies that the series name should be shown in the data label.
+     *
+     * @var boolean
+     */
+    private $showSerName;
+
+    /**
+     * show percentage
+     * Specifies that the percentage should be shown in the data label.
+     *
+     * @var boolean
+     */
+    private $showPercent;
+
+    /**
+     * show bubble size
+     *
+     * @var boolean
+     */
+    private $showBubbleSize;
+
+    /**
+     * show leader lines
+     * Specifies that leader lines should be shown for the data label.
+     *
+     * @var boolean
+     */
+    private $showLeaderLines;
+
+
+    /**
+     * Create a new PHPExcel_Chart_Layout
+     */
+    public function __construct($layout = array())
+    {
+        if (isset($layout['layoutTarget'])) {
+            $this->layoutTarget = $layout['layoutTarget'];
+        }
+        if (isset($layout['xMode'])) {
+            $this->xMode = $layout['xMode'];
+        }
+        if (isset($layout['yMode'])) {
+            $this->yMode = $layout['yMode'];
+        }
+        if (isset($layout['x'])) {
+            $this->xPos = (float) $layout['x'];
+        }
+        if (isset($layout['y'])) {
+            $this->yPos = (float) $layout['y'];
+        }
+        if (isset($layout['w'])) {
+            $this->width = (float) $layout['w'];
+        }
+        if (isset($layout['h'])) {
+            $this->height = (float) $layout['h'];
+        }
+    }
+
+    /**
+     * Get Layout Target
+     *
+     * @return string
+     */
+    public function getLayoutTarget()
+    {
+        return $this->layoutTarget;
+    }
+
+    /**
+     * Set Layout Target
+     *
+     * @param Layout Target $value
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setLayoutTarget($value)
+    {
+        $this->layoutTarget = $value;
+        return $this;
+    }
+
+    /**
+     * Get X-Mode
+     *
+     * @return string
+     */
+    public function getXMode()
+    {
+        return $this->xMode;
+    }
+
+    /**
+     * Set X-Mode
+     *
+     * @param X-Mode $value
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setXMode($value)
+    {
+        $this->xMode = $value;
+        return $this;
+    }
+
+    /**
+     * Get Y-Mode
+     *
+     * @return string
+     */
+    public function getYMode()
+    {
+        return $this->yMode;
+    }
+
+    /**
+     * Set Y-Mode
+     *
+     * @param Y-Mode $value
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setYMode($value)
+    {
+        $this->yMode = $value;
+        return $this;
+    }
+
+    /**
+     * Get X-Position
+     *
+     * @return number
+     */
+    public function getXPosition()
+    {
+        return $this->xPos;
+    }
+
+    /**
+     * Set X-Position
+     *
+     * @param X-Position $value
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setXPosition($value)
+    {
+        $this->xPos = $value;
+        return $this;
+    }
+
+    /**
+     * Get Y-Position
+     *
+     * @return number
+     */
+    public function getYPosition()
+    {
+        return $this->yPos;
+    }
+
+    /**
+     * Set Y-Position
+     *
+     * @param Y-Position $value
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setYPosition($value)
+    {
+        $this->yPos = $value;
+        return $this;
+    }
+
+    /**
+     * Get Width
+     *
+     * @return number
+     */
+    public function getWidth()
+    {
+        return $this->width;
+    }
+
+    /**
+     * Set Width
+     *
+     * @param Width $value
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setWidth($value)
+    {
+        $this->width = $value;
+        return $this;
+    }
+
+    /**
+     * Get Height
+     *
+     * @return number
+     */
+    public function getHeight()
+    {
+        return $this->height;
+    }
+
+    /**
+     * Set Height
+     *
+     * @param Height $value
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setHeight($value)
+    {
+        $this->height = $value;
+        return $this;
+    }
+
+
+    /**
+     * Get show legend key
+     *
+     * @return boolean
+     */
+    public function getShowLegendKey()
+    {
+        return $this->showLegendKey;
+    }
+
+    /**
+     * Set show legend key
+     * Specifies that legend keys should be shown in data labels.
+     *
+     * @param boolean $value        Show legend key
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setShowLegendKey($value)
+    {
+        $this->showLegendKey = $value;
+        return $this;
+    }
+
+    /**
+     * Get show value
+     *
+     * @return boolean
+     */
+    public function getShowVal()
+    {
+        return $this->showVal;
+    }
+
+    /**
+     * Set show val
+     * Specifies that the value should be shown in data labels.
+     *
+     * @param boolean $value        Show val
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setShowVal($value)
+    {
+        $this->showVal = $value;
+        return $this;
+    }
+
+    /**
+     * Get show category name
+     *
+     * @return boolean
+     */
+    public function getShowCatName()
+    {
+        return $this->showCatName;
+    }
+
+    /**
+     * Set show cat name
+     * Specifies that the category name should be shown in data labels.
+     *
+     * @param boolean $value        Show cat name
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setShowCatName($value)
+    {
+        $this->showCatName = $value;
+        return $this;
+    }
+
+    /**
+     * Get show data series name
+     *
+     * @return boolean
+     */
+    public function getShowSerName()
+    {
+        return $this->showSerName;
+    }
+
+    /**
+     * Set show ser name
+     * Specifies that the series name should be shown in data labels.
+     *
+     * @param boolean $value        Show series name
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setShowSerName($value)
+    {
+        $this->showSerName = $value;
+        return $this;
+    }
+
+    /**
+     * Get show percentage
+     *
+     * @return boolean
+     */
+    public function getShowPercent()
+    {
+        return $this->showPercent;
+    }
+
+    /**
+     * Set show percentage
+     * Specifies that the percentage should be shown in data labels.
+     *
+     * @param boolean $value        Show percentage
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setShowPercent($value)
+    {
+        $this->showPercent = $value;
+        return $this;
+    }
+
+    /**
+     * Get show bubble size
+     *
+     * @return boolean
+     */
+    public function getShowBubbleSize()
+    {
+        return $this->showBubbleSize;
+    }
+
+    /**
+     * Set show bubble size
+     * Specifies that the bubble size should be shown in data labels.
+     *
+     * @param boolean $value        Show bubble size
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setShowBubbleSize($value)
+    {
+        $this->showBubbleSize = $value;
+        return $this;
+    }
+
+    /**
+     * Get show leader lines
+     *
+     * @return boolean
+     */
+    public function getShowLeaderLines()
+    {
+        return $this->showLeaderLines;
+    }
+
+    /**
+     * Set show leader lines
+     * Specifies that leader lines should be shown in data labels.
+     *
+     * @param boolean $value        Show leader lines
+     * @return PHPExcel_Chart_Layout
+     */
+    public function setShowLeaderLines($value)
+    {
+        $this->showLeaderLines = $value;
+        return $this;
+    }
+}

+ 170 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Legend.php

@@ -0,0 +1,170 @@
+<?php
+
+/**
+ * PHPExcel_Chart_Legend
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Chart_Legend
+{
+    /** Legend positions */
+    const xlLegendPositionBottom = -4107;    //    Below the chart.
+    const xlLegendPositionCorner = 2;        //    In the upper right-hand corner of the chart border.
+    const xlLegendPositionCustom = -4161;    //    A custom position.
+    const xlLegendPositionLeft   = -4131;    //    Left of the chart.
+    const xlLegendPositionRight  = -4152;    //    Right of the chart.
+    const xlLegendPositionTop    = -4160;    //    Above the chart.
+
+    const POSITION_RIGHT    = 'r';
+    const POSITION_LEFT     = 'l';
+    const POSITION_BOTTOM   = 'b';
+    const POSITION_TOP      = 't';
+    const POSITION_TOPRIGHT = 'tr';
+
+    private static $positionXLref = array(
+        self::xlLegendPositionBottom => self::POSITION_BOTTOM,
+        self::xlLegendPositionCorner => self::POSITION_TOPRIGHT,
+        self::xlLegendPositionCustom => '??',
+        self::xlLegendPositionLeft   => self::POSITION_LEFT,
+        self::xlLegendPositionRight  => self::POSITION_RIGHT,
+        self::xlLegendPositionTop    => self::POSITION_TOP
+    );
+
+    /**
+     * Legend position
+     *
+     * @var    string
+     */
+    private $position = self::POSITION_RIGHT;
+
+    /**
+     * Allow overlay of other elements?
+     *
+     * @var    boolean
+     */
+    private $overlay = true;
+
+    /**
+     * Legend Layout
+     *
+     * @var    PHPExcel_Chart_Layout
+     */
+    private $layout = null;
+
+
+    /**
+     *    Create a new PHPExcel_Chart_Legend
+     */
+    public function __construct($position = self::POSITION_RIGHT, PHPExcel_Chart_Layout $layout = null, $overlay = false)
+    {
+        $this->setPosition($position);
+        $this->layout = $layout;
+        $this->setOverlay($overlay);
+    }
+
+    /**
+     * Get legend position as an excel string value
+     *
+     * @return    string
+     */
+    public function getPosition()
+    {
+        return $this->position;
+    }
+
+    /**
+     * Get legend position using an excel string value
+     *
+     * @param    string    $position
+     */
+    public function setPosition($position = self::POSITION_RIGHT)
+    {
+        if (!in_array($position, self::$positionXLref)) {
+            return false;
+        }
+
+        $this->position = $position;
+        return true;
+    }
+
+    /**
+     * Get legend position as an Excel internal numeric value
+     *
+     * @return    number
+     */
+    public function getPositionXL()
+    {
+        return array_search($this->position, self::$positionXLref);
+    }
+
+    /**
+     * Set legend position using an Excel internal numeric value
+     *
+     * @param    number    $positionXL
+     */
+    public function setPositionXL($positionXL = self::xlLegendPositionRight)
+    {
+        if (!array_key_exists($positionXL, self::$positionXLref)) {
+            return false;
+        }
+
+        $this->position = self::$positionXLref[$positionXL];
+        return true;
+    }
+
+    /**
+     * Get allow overlay of other elements?
+     *
+     * @return    boolean
+     */
+    public function getOverlay()
+    {
+        return $this->overlay;
+    }
+
+    /**
+     * Set allow overlay of other elements?
+     *
+     * @param    boolean    $overlay
+     * @return    boolean
+     */
+    public function setOverlay($overlay = false)
+    {
+        if (!is_bool($overlay)) {
+            return false;
+        }
+
+        $this->overlay = $overlay;
+        return true;
+    }
+
+    /**
+     * Get Layout
+     *
+     * @return PHPExcel_Chart_Layout
+     */
+    public function getLayout()
+    {
+        return $this->layout;
+    }
+}

+ 126 - 0
backend/RTP/extend/excel/PHPExcel/Chart/PlotArea.php

@@ -0,0 +1,126 @@
+<?php
+
+/**
+ * PHPExcel_Chart_PlotArea
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Chart_PlotArea
+{
+    /**
+     * PlotArea Layout
+     *
+     * @var PHPExcel_Chart_Layout
+     */
+    private $layout = null;
+
+    /**
+     * Plot Series
+     *
+     * @var array of PHPExcel_Chart_DataSeries
+     */
+    private $plotSeries = array();
+
+    /**
+     * Create a new PHPExcel_Chart_PlotArea
+     */
+    public function __construct(PHPExcel_Chart_Layout $layout = null, $plotSeries = array())
+    {
+        $this->layout = $layout;
+        $this->plotSeries = $plotSeries;
+    }
+
+    /**
+     * Get Layout
+     *
+     * @return PHPExcel_Chart_Layout
+     */
+    public function getLayout()
+    {
+        return $this->layout;
+    }
+
+    /**
+     * Get Number of Plot Groups
+     *
+     * @return array of PHPExcel_Chart_DataSeries
+     */
+    public function getPlotGroupCount()
+    {
+        return count($this->plotSeries);
+    }
+
+    /**
+     * Get Number of Plot Series
+     *
+     * @return integer
+     */
+    public function getPlotSeriesCount()
+    {
+        $seriesCount = 0;
+        foreach ($this->plotSeries as $plot) {
+            $seriesCount += $plot->getPlotSeriesCount();
+        }
+        return $seriesCount;
+    }
+
+    /**
+     * Get Plot Series
+     *
+     * @return array of PHPExcel_Chart_DataSeries
+     */
+    public function getPlotGroup()
+    {
+        return $this->plotSeries;
+    }
+
+    /**
+     * Get Plot Series by Index
+     *
+     * @return PHPExcel_Chart_DataSeries
+     */
+    public function getPlotGroupByIndex($index)
+    {
+        return $this->plotSeries[$index];
+    }
+
+    /**
+     * Set Plot Series
+     *
+     * @param [PHPExcel_Chart_DataSeries]
+     * @return PHPExcel_Chart_PlotArea
+     */
+    public function setPlotSeries($plotSeries = array())
+    {
+        $this->plotSeries = $plotSeries;
+        
+        return $this;
+    }
+
+    public function refresh(PHPExcel_Worksheet $worksheet)
+    {
+        foreach ($this->plotSeries as $plotSeries) {
+            $plotSeries->refresh($worksheet);
+        }
+    }
+}

+ 363 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Properties.php

@@ -0,0 +1,363 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: nhw2h8s
+ * Date: 7/2/14
+ * Time: 5:45 PM
+ */
+
+abstract class PHPExcel_Chart_Properties
+{
+    const
+        EXCEL_COLOR_TYPE_STANDARD = 'prstClr',
+        EXCEL_COLOR_TYPE_SCHEME = 'schemeClr',
+        EXCEL_COLOR_TYPE_ARGB = 'srgbClr';
+
+    const
+        AXIS_LABELS_LOW = 'low',
+        AXIS_LABELS_HIGH = 'high',
+        AXIS_LABELS_NEXT_TO = 'nextTo',
+        AXIS_LABELS_NONE = 'none';
+
+    const
+        TICK_MARK_NONE = 'none',
+        TICK_MARK_INSIDE = 'in',
+        TICK_MARK_OUTSIDE = 'out',
+        TICK_MARK_CROSS = 'cross';
+
+    const
+        HORIZONTAL_CROSSES_AUTOZERO = 'autoZero',
+        HORIZONTAL_CROSSES_MAXIMUM = 'max';
+
+    const
+        FORMAT_CODE_GENERAL = 'General',
+        FORMAT_CODE_NUMBER = '#,##0.00',
+        FORMAT_CODE_CURRENCY = '$#,##0.00',
+        FORMAT_CODE_ACCOUNTING = '_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_)',
+        FORMAT_CODE_DATE = 'm/d/yyyy',
+        FORMAT_CODE_TIME = '[$-F400]h:mm:ss AM/PM',
+        FORMAT_CODE_PERCENTAGE = '0.00%',
+        FORMAT_CODE_FRACTION = '# ?/?',
+        FORMAT_CODE_SCIENTIFIC = '0.00E+00',
+        FORMAT_CODE_TEXT = '@',
+        FORMAT_CODE_SPECIAL = '00000';
+
+    const
+        ORIENTATION_NORMAL = 'minMax',
+        ORIENTATION_REVERSED = 'maxMin';
+
+    const
+        LINE_STYLE_COMPOUND_SIMPLE = 'sng',
+        LINE_STYLE_COMPOUND_DOUBLE = 'dbl',
+        LINE_STYLE_COMPOUND_THICKTHIN = 'thickThin',
+        LINE_STYLE_COMPOUND_THINTHICK = 'thinThick',
+        LINE_STYLE_COMPOUND_TRIPLE = 'tri',
+
+        LINE_STYLE_DASH_SOLID = 'solid',
+        LINE_STYLE_DASH_ROUND_DOT = 'sysDot',
+        LINE_STYLE_DASH_SQUERE_DOT = 'sysDash',
+        LINE_STYPE_DASH_DASH = 'dash',
+        LINE_STYLE_DASH_DASH_DOT = 'dashDot',
+        LINE_STYLE_DASH_LONG_DASH = 'lgDash',
+        LINE_STYLE_DASH_LONG_DASH_DOT = 'lgDashDot',
+        LINE_STYLE_DASH_LONG_DASH_DOT_DOT = 'lgDashDotDot',
+
+        LINE_STYLE_CAP_SQUARE = 'sq',
+        LINE_STYLE_CAP_ROUND = 'rnd',
+        LINE_STYLE_CAP_FLAT = 'flat',
+
+        LINE_STYLE_JOIN_ROUND = 'bevel',
+        LINE_STYLE_JOIN_MITER = 'miter',
+        LINE_STYLE_JOIN_BEVEL = 'bevel',
+
+        LINE_STYLE_ARROW_TYPE_NOARROW = null,
+        LINE_STYLE_ARROW_TYPE_ARROW = 'triangle',
+        LINE_STYLE_ARROW_TYPE_OPEN = 'arrow',
+        LINE_STYLE_ARROW_TYPE_STEALTH = 'stealth',
+        LINE_STYLE_ARROW_TYPE_DIAMOND = 'diamond',
+        LINE_STYLE_ARROW_TYPE_OVAL = 'oval',
+
+        LINE_STYLE_ARROW_SIZE_1 = 1,
+        LINE_STYLE_ARROW_SIZE_2 = 2,
+        LINE_STYLE_ARROW_SIZE_3 = 3,
+        LINE_STYLE_ARROW_SIZE_4 = 4,
+        LINE_STYLE_ARROW_SIZE_5 = 5,
+        LINE_STYLE_ARROW_SIZE_6 = 6,
+        LINE_STYLE_ARROW_SIZE_7 = 7,
+        LINE_STYLE_ARROW_SIZE_8 = 8,
+        LINE_STYLE_ARROW_SIZE_9 = 9;
+
+    const
+        SHADOW_PRESETS_NOSHADOW = null,
+        SHADOW_PRESETS_OUTER_BOTTTOM_RIGHT = 1,
+        SHADOW_PRESETS_OUTER_BOTTOM = 2,
+        SHADOW_PRESETS_OUTER_BOTTOM_LEFT = 3,
+        SHADOW_PRESETS_OUTER_RIGHT = 4,
+        SHADOW_PRESETS_OUTER_CENTER = 5,
+        SHADOW_PRESETS_OUTER_LEFT = 6,
+        SHADOW_PRESETS_OUTER_TOP_RIGHT = 7,
+        SHADOW_PRESETS_OUTER_TOP = 8,
+        SHADOW_PRESETS_OUTER_TOP_LEFT = 9,
+        SHADOW_PRESETS_INNER_BOTTTOM_RIGHT = 10,
+        SHADOW_PRESETS_INNER_BOTTOM = 11,
+        SHADOW_PRESETS_INNER_BOTTOM_LEFT = 12,
+        SHADOW_PRESETS_INNER_RIGHT = 13,
+        SHADOW_PRESETS_INNER_CENTER = 14,
+        SHADOW_PRESETS_INNER_LEFT = 15,
+        SHADOW_PRESETS_INNER_TOP_RIGHT = 16,
+        SHADOW_PRESETS_INNER_TOP = 17,
+        SHADOW_PRESETS_INNER_TOP_LEFT = 18,
+        SHADOW_PRESETS_PERSPECTIVE_BELOW = 19,
+        SHADOW_PRESETS_PERSPECTIVE_UPPER_RIGHT = 20,
+        SHADOW_PRESETS_PERSPECTIVE_UPPER_LEFT = 21,
+        SHADOW_PRESETS_PERSPECTIVE_LOWER_RIGHT = 22,
+        SHADOW_PRESETS_PERSPECTIVE_LOWER_LEFT = 23;
+
+    protected function getExcelPointsWidth($width)
+    {
+        return $width * 12700;
+    }
+
+    protected function getExcelPointsAngle($angle)
+    {
+        return $angle * 60000;
+    }
+
+    protected function getTrueAlpha($alpha)
+    {
+        return (string) 100 - $alpha . '000';
+    }
+
+    protected function setColorProperties($color, $alpha, $type)
+    {
+        return array(
+            'type' => (string) $type,
+            'value' => (string) $color,
+            'alpha' => (string) $this->getTrueAlpha($alpha)
+        );
+    }
+
+    protected function getLineStyleArrowSize($array_selector, $array_kay_selector)
+    {
+        $sizes = array(
+            1 => array('w' => 'sm', 'len' => 'sm'),
+            2 => array('w' => 'sm', 'len' => 'med'),
+            3 => array('w' => 'sm', 'len' => 'lg'),
+            4 => array('w' => 'med', 'len' => 'sm'),
+            5 => array('w' => 'med', 'len' => 'med'),
+            6 => array('w' => 'med', 'len' => 'lg'),
+            7 => array('w' => 'lg', 'len' => 'sm'),
+            8 => array('w' => 'lg', 'len' => 'med'),
+            9 => array('w' => 'lg', 'len' => 'lg')
+        );
+
+        return $sizes[$array_selector][$array_kay_selector];
+    }
+
+    protected function getShadowPresetsMap($shadow_presets_option)
+    {
+        $presets_options = array(
+            //OUTER
+            1 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'direction' => '2700000',
+                'algn' => 'tl',
+                'rotWithShape' => '0'
+            ),
+            2 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'direction' => '5400000',
+                'algn' => 't',
+                'rotWithShape' => '0'
+            ),
+            3 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'direction' => '8100000',
+                'algn' => 'tr',
+                'rotWithShape' => '0'
+            ),
+            4 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'algn' => 'l',
+                'rotWithShape' => '0'
+            ),
+            5 => array(
+                'effect' => 'outerShdw',
+                'size' => array(
+                    'sx' => '102000',
+                    'sy' => '102000'
+                )
+                ,
+                'blur' => '63500',
+                'distance' => '38100',
+                'algn' => 'ctr',
+                'rotWithShape' => '0'
+            ),
+            6 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'direction' => '10800000',
+                'algn' => 'r',
+                'rotWithShape' => '0'
+            ),
+            7 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'direction' => '18900000',
+                'algn' => 'bl',
+                'rotWithShape' => '0'
+            ),
+            8 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'direction' => '16200000',
+                'rotWithShape' => '0'
+            ),
+            9 => array(
+                'effect' => 'outerShdw',
+                'blur' => '50800',
+                'distance' => '38100',
+                'direction' => '13500000',
+                'algn' => 'br',
+                'rotWithShape' => '0'
+            ),
+            //INNER
+            10 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+                'direction' => '2700000',
+            ),
+            11 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+                'direction' => '5400000',
+            ),
+            12 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+                'direction' => '8100000',
+            ),
+            13 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+            ),
+            14 => array(
+                'effect' => 'innerShdw',
+                'blur' => '114300',
+            ),
+            15 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+                'direction' => '10800000',
+            ),
+            16 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+                'direction' => '18900000',
+            ),
+            17 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+                'direction' => '16200000',
+            ),
+            18 => array(
+                'effect' => 'innerShdw',
+                'blur' => '63500',
+                'distance' => '50800',
+                'direction' => '13500000',
+            ),
+            //perspective
+            19 => array(
+                'effect' => 'outerShdw',
+                'blur' => '152400',
+                'distance' => '317500',
+                'size' => array(
+                    'sx' => '90000',
+                    'sy' => '-19000',
+                ),
+                'direction' => '5400000',
+                'rotWithShape' => '0',
+            ),
+            20 => array(
+                'effect' => 'outerShdw',
+                'blur' => '76200',
+                'direction' => '18900000',
+                'size' => array(
+                    'sy' => '23000',
+                    'kx' => '-1200000',
+                ),
+                'algn' => 'bl',
+                'rotWithShape' => '0',
+            ),
+            21 => array(
+                'effect' => 'outerShdw',
+                'blur' => '76200',
+                'direction' => '13500000',
+                'size' => array(
+                    'sy' => '23000',
+                    'kx' => '1200000',
+                ),
+                'algn' => 'br',
+                'rotWithShape' => '0',
+            ),
+            22 => array(
+                'effect' => 'outerShdw',
+                'blur' => '76200',
+                'distance' => '12700',
+                'direction' => '2700000',
+                'size' => array(
+                    'sy' => '-23000',
+                    'kx' => '-800400',
+                ),
+                'algn' => 'bl',
+                'rotWithShape' => '0',
+            ),
+            23 => array(
+                'effect' => 'outerShdw',
+                'blur' => '76200',
+                'distance' => '12700',
+                'direction' => '8100000',
+                'size' => array(
+                    'sy' => '-23000',
+                    'kx' => '800400',
+                ),
+                'algn' => 'br',
+                'rotWithShape' => '0',
+            ),
+        );
+
+        return $presets_options[$shadow_presets_option];
+    }
+
+    protected function getArrayElementsValue($properties, $elements)
+    {
+        $reference = & $properties;
+        if (!is_array($elements)) {
+            return $reference[$elements];
+        } else {
+            foreach ($elements as $keys) {
+                $reference = & $reference[$keys];
+            }
+            return $reference;
+        }
+        return $this;
+    }
+}

+ 20 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt

@@ -0,0 +1,20 @@
+ChartDirector
+	http://www.advsofteng.com/cdphp.html
+
+GraPHPite
+	http://graphpite.sourceforge.net/
+
+JpGraph
+	http://www.aditus.nu/jpgraph/
+
+LibChart
+	http://naku.dohcrew.com/libchart/pages/introduction/
+
+pChart
+	http://pchart.sourceforge.net/
+
+TeeChart
+	http://www.steema.com/products/teechart/overview.html
+
+PHPGraphLib
+    http://www.ebrueggeman.com/phpgraphlib

+ 883 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Renderer/jpgraph.php

@@ -0,0 +1,883 @@
+<?php
+
+require_once(PHPExcel_Settings::getChartRendererPath().'/jpgraph.php');
+
+/**
+ * PHPExcel_Chart_Renderer_jpgraph
+ *
+ * Copyright (c) 2006 - 2015 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_Chart_Renderer
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Chart_Renderer_jpgraph
+{
+    private static $width    = 640;
+
+    private static $height    = 480;
+
+    private static $colourSet = array(
+        'mediumpurple1',    'palegreen3',     'gold1',          'cadetblue1',
+        'darkmagenta',      'coral',          'dodgerblue3',    'eggplant',
+        'mediumblue',       'magenta',        'sandybrown',     'cyan',
+        'firebrick1',       'forestgreen',    'deeppink4',      'darkolivegreen',
+        'goldenrod2'
+    );
+
+    private static $markSet = array(
+        'diamond'  => MARK_DIAMOND,
+        'square'   => MARK_SQUARE,
+        'triangle' => MARK_UTRIANGLE,
+        'x'        => MARK_X,
+        'star'     => MARK_STAR,
+        'dot'      => MARK_FILLEDCIRCLE,
+        'dash'     => MARK_DTRIANGLE,
+        'circle'   => MARK_CIRCLE,
+        'plus'     => MARK_CROSS
+    );
+
+
+    private $chart;
+
+    private $graph;
+
+    private static $plotColour = 0;
+
+    private static $plotMark = 0;
+
+
+    private function formatPointMarker($seriesPlot, $markerID)
+    {
+        $plotMarkKeys = array_keys(self::$markSet);
+        if (is_null($markerID)) {
+            //    Use default plot marker (next marker in the series)
+            self::$plotMark %= count(self::$markSet);
+            $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
+        } elseif ($markerID !== 'none') {
+            //    Use specified plot marker (if it exists)
+            if (isset(self::$markSet[$markerID])) {
+                $seriesPlot->mark->SetType(self::$markSet[$markerID]);
+            } else {
+                //    If the specified plot marker doesn't exist, use default plot marker (next marker in the series)
+                self::$plotMark %= count(self::$markSet);
+                $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
+            }
+        } else {
+            //    Hide plot marker
+            $seriesPlot->mark->Hide();
+        }
+        $seriesPlot->mark->SetColor(self::$colourSet[self::$plotColour]);
+        $seriesPlot->mark->SetFillColor(self::$colourSet[self::$plotColour]);
+        $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+
+        return $seriesPlot;
+    }
+
+
+    private function formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation = '')
+    {
+        $datasetLabelFormatCode = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getFormatCode();
+        if (!is_null($datasetLabelFormatCode)) {
+            //    Retrieve any label formatting code
+            $datasetLabelFormatCode = stripslashes($datasetLabelFormatCode);
+        }
+
+        $testCurrentIndex = 0;
+        foreach ($datasetLabels as $i => $datasetLabel) {
+            if (is_array($datasetLabel)) {
+                if ($rotation == 'bar') {
+                    $datasetLabels[$i] = implode(" ", $datasetLabel);
+                } else {
+                    $datasetLabel = array_reverse($datasetLabel);
+                    $datasetLabels[$i] = implode("\n", $datasetLabel);
+                }
+            } else {
+                //    Format labels according to any formatting code
+                if (!is_null($datasetLabelFormatCode)) {
+                    $datasetLabels[$i] = PHPExcel_Style_NumberFormat::toFormattedString($datasetLabel, $datasetLabelFormatCode);
+                }
+            }
+            ++$testCurrentIndex;
+        }
+
+        return $datasetLabels;
+    }
+
+
+    private function percentageSumCalculation($groupID, $seriesCount)
+    {
+        //    Adjust our values to a percentage value across all series in the group
+        for ($i = 0; $i < $seriesCount; ++$i) {
+            if ($i == 0) {
+                $sumValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+            } else {
+                $nextValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+                foreach ($nextValues as $k => $value) {
+                    if (isset($sumValues[$k])) {
+                        $sumValues[$k] += $value;
+                    } else {
+                        $sumValues[$k] = $value;
+                    }
+                }
+            }
+        }
+
+        return $sumValues;
+    }
+
+
+    private function percentageAdjustValues($dataValues, $sumValues)
+    {
+        foreach ($dataValues as $k => $dataValue) {
+            $dataValues[$k] = $dataValue / $sumValues[$k] * 100;
+        }
+
+        return $dataValues;
+    }
+
+
+    private function getCaption($captionElement)
+    {
+        //    Read any caption
+        $caption = (!is_null($captionElement)) ? $captionElement->getCaption() : null;
+        //    Test if we have a title caption to display
+        if (!is_null($caption)) {
+            //    If we do, it could be a plain string or an array
+            if (is_array($caption)) {
+                //    Implode an array to a plain string
+                $caption = implode('', $caption);
+            }
+        }
+        return $caption;
+    }
+
+
+    private function renderTitle()
+    {
+        $title = $this->getCaption($this->chart->getTitle());
+        if (!is_null($title)) {
+            $this->graph->title->Set($title);
+        }
+    }
+
+
+    private function renderLegend()
+    {
+        $legend = $this->chart->getLegend();
+        if (!is_null($legend)) {
+            $legendPosition = $legend->getPosition();
+            $legendOverlay = $legend->getOverlay();
+            switch ($legendPosition) {
+                case 'r':
+                    $this->graph->legend->SetPos(0.01, 0.5, 'right', 'center');    //    right
+                    $this->graph->legend->SetColumns(1);
+                    break;
+                case 'l':
+                    $this->graph->legend->SetPos(0.01, 0.5, 'left', 'center');    //    left
+                    $this->graph->legend->SetColumns(1);
+                    break;
+                case 't':
+                    $this->graph->legend->SetPos(0.5, 0.01, 'center', 'top');    //    top
+                    break;
+                case 'b':
+                    $this->graph->legend->SetPos(0.5, 0.99, 'center', 'bottom');    //    bottom
+                    break;
+                default:
+                    $this->graph->legend->SetPos(0.01, 0.01, 'right', 'top');    //    top-right
+                    $this->graph->legend->SetColumns(1);
+                    break;
+            }
+        } else {
+            $this->graph->legend->Hide();
+        }
+    }
+
+
+    private function renderCartesianPlotArea($type = 'textlin')
+    {
+        $this->graph = new Graph(self::$width, self::$height);
+        $this->graph->SetScale($type);
+
+        $this->renderTitle();
+
+        //    Rotate for bar rather than column chart
+        $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotDirection();
+        $reverse = ($rotation == 'bar') ? true : false;
+
+        $xAxisLabel = $this->chart->getXAxisLabel();
+        if (!is_null($xAxisLabel)) {
+            $title = $this->getCaption($xAxisLabel);
+            if (!is_null($title)) {
+                $this->graph->xaxis->SetTitle($title, 'center');
+                $this->graph->xaxis->title->SetMargin(35);
+                if ($reverse) {
+                    $this->graph->xaxis->title->SetAngle(90);
+                    $this->graph->xaxis->title->SetMargin(90);
+                }
+            }
+        }
+
+        $yAxisLabel = $this->chart->getYAxisLabel();
+        if (!is_null($yAxisLabel)) {
+            $title = $this->getCaption($yAxisLabel);
+            if (!is_null($title)) {
+                $this->graph->yaxis->SetTitle($title, 'center');
+                if ($reverse) {
+                    $this->graph->yaxis->title->SetAngle(0);
+                    $this->graph->yaxis->title->SetMargin(-55);
+                }
+            }
+        }
+    }
+
+
+    private function renderPiePlotArea($doughnut = false)
+    {
+        $this->graph = new PieGraph(self::$width, self::$height);
+
+        $this->renderTitle();
+    }
+
+
+    private function renderRadarPlotArea()
+    {
+        $this->graph = new RadarGraph(self::$width, self::$height);
+        $this->graph->SetScale('lin');
+
+        $this->renderTitle();
+    }
+
+
+    private function renderPlotLine($groupID, $filled = false, $combination = false, $dimensions = '2d')
+    {
+        $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+        $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+        if ($labelCount > 0) {
+            $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+            $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+            $this->graph->xaxis->SetTickLabels($datasetLabels);
+        }
+
+        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+        $seriesPlots = array();
+        if ($grouping == 'percentStacked') {
+            $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
+        }
+
+        //    Loop through each data series in turn
+        for ($i = 0; $i < $seriesCount; ++$i) {
+            $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+            $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+            if ($grouping == 'percentStacked') {
+                $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
+            }
+
+            //    Fill in any missing values in the $dataValues array
+            $testCurrentIndex = 0;
+            foreach ($dataValues as $k => $dataValue) {
+                while ($k != $testCurrentIndex) {
+                    $dataValues[$testCurrentIndex] = null;
+                    ++$testCurrentIndex;
+                }
+                ++$testCurrentIndex;
+            }
+
+            $seriesPlot = new LinePlot($dataValues);
+            if ($combination) {
+                $seriesPlot->SetBarCenter();
+            }
+
+            if ($filled) {
+                $seriesPlot->SetFilled(true);
+                $seriesPlot->SetColor('black');
+                $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
+            } else {
+                //    Set the appropriate plot marker
+                $this->formatPointMarker($seriesPlot, $marker);
+            }
+            $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+            $seriesPlot->SetLegend($dataLabel);
+
+            $seriesPlots[] = $seriesPlot;
+        }
+
+        if ($grouping == 'standard') {
+            $groupPlot = $seriesPlots;
+        } else {
+            $groupPlot = new AccLinePlot($seriesPlots);
+        }
+        $this->graph->Add($groupPlot);
+    }
+
+
+    private function renderPlotBar($groupID, $dimensions = '2d')
+    {
+        $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotDirection();
+        //    Rotate for bar rather than column chart
+        if (($groupID == 0) && ($rotation == 'bar')) {
+            $this->graph->Set90AndMargin();
+        }
+        $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+        $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+        if ($labelCount > 0) {
+            $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+            $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation);
+            //    Rotate for bar rather than column chart
+            if ($rotation == 'bar') {
+                $datasetLabels = array_reverse($datasetLabels);
+                $this->graph->yaxis->SetPos('max');
+                $this->graph->yaxis->SetLabelAlign('center', 'top');
+                $this->graph->yaxis->SetLabelSide(SIDE_RIGHT);
+            }
+            $this->graph->xaxis->SetTickLabels($datasetLabels);
+        }
+
+
+        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+        $seriesPlots = array();
+        if ($grouping == 'percentStacked') {
+            $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
+        }
+
+        //    Loop through each data series in turn
+        for ($j = 0; $j < $seriesCount; ++$j) {
+            $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+            if ($grouping == 'percentStacked') {
+                $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
+            }
+
+            //    Fill in any missing values in the $dataValues array
+            $testCurrentIndex = 0;
+            foreach ($dataValues as $k => $dataValue) {
+                while ($k != $testCurrentIndex) {
+                    $dataValues[$testCurrentIndex] = null;
+                    ++$testCurrentIndex;
+                }
+                ++$testCurrentIndex;
+            }
+
+            //    Reverse the $dataValues order for bar rather than column chart
+            if ($rotation == 'bar') {
+                $dataValues = array_reverse($dataValues);
+            }
+            $seriesPlot = new BarPlot($dataValues);
+            $seriesPlot->SetColor('black');
+            $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
+            if ($dimensions == '3d') {
+                $seriesPlot->SetShadow();
+            }
+            if (!$this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)) {
+                $dataLabel = '';
+            } else {
+                $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)->getDataValue();
+            }
+            $seriesPlot->SetLegend($dataLabel);
+
+            $seriesPlots[] = $seriesPlot;
+        }
+        //    Reverse the plot order for bar rather than column chart
+        if (($rotation == 'bar') && (!($grouping == 'percentStacked'))) {
+            $seriesPlots = array_reverse($seriesPlots);
+        }
+
+        if ($grouping == 'clustered') {
+            $groupPlot = new GroupBarPlot($seriesPlots);
+        } elseif ($grouping == 'standard') {
+            $groupPlot = new GroupBarPlot($seriesPlots);
+        } else {
+            $groupPlot = new AccBarPlot($seriesPlots);
+            if ($dimensions == '3d') {
+                $groupPlot->SetShadow();
+            }
+        }
+
+        $this->graph->Add($groupPlot);
+    }
+
+
+    private function renderPlotScatter($groupID, $bubble)
+    {
+        $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+        $scatterStyle = $bubbleSize = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+        $seriesPlots = array();
+
+        //    Loop through each data series in turn
+        for ($i = 0; $i < $seriesCount; ++$i) {
+            $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+            $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+            foreach ($dataValuesY as $k => $dataValueY) {
+                $dataValuesY[$k] = $k;
+            }
+
+            $seriesPlot = new ScatterPlot($dataValuesX, $dataValuesY);
+            if ($scatterStyle == 'lineMarker') {
+                $seriesPlot->SetLinkPoints();
+                $seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
+            } elseif ($scatterStyle == 'smoothMarker') {
+                $spline = new Spline($dataValuesY, $dataValuesX);
+                list($splineDataY, $splineDataX) = $spline->Get(count($dataValuesX) * self::$width / 20);
+                $lplot = new LinePlot($splineDataX, $splineDataY);
+                $lplot->SetColor(self::$colourSet[self::$plotColour]);
+
+                $this->graph->Add($lplot);
+            }
+
+            if ($bubble) {
+                $this->formatPointMarker($seriesPlot, 'dot');
+                $seriesPlot->mark->SetColor('black');
+                $seriesPlot->mark->SetSize($bubbleSize);
+            } else {
+                $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+                $this->formatPointMarker($seriesPlot, $marker);
+            }
+            $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+            $seriesPlot->SetLegend($dataLabel);
+
+            $this->graph->Add($seriesPlot);
+        }
+    }
+
+
+    private function renderPlotRadar($groupID)
+    {
+        $radarStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+        $seriesPlots = array();
+
+        //    Loop through each data series in turn
+        for ($i = 0; $i < $seriesCount; ++$i) {
+            $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+            $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+            $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+            $dataValues = array();
+            foreach ($dataValuesY as $k => $dataValueY) {
+                $dataValues[$k] = implode(' ', array_reverse($dataValueY));
+            }
+            $tmp = array_shift($dataValues);
+            $dataValues[] = $tmp;
+            $tmp = array_shift($dataValuesX);
+            $dataValuesX[] = $tmp;
+
+            $this->graph->SetTitles(array_reverse($dataValues));
+
+            $seriesPlot = new RadarPlot(array_reverse($dataValuesX));
+
+            $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+            $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+            if ($radarStyle == 'filled') {
+                $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour]);
+            }
+            $this->formatPointMarker($seriesPlot, $marker);
+            $seriesPlot->SetLegend($dataLabel);
+
+            $this->graph->Add($seriesPlot);
+        }
+    }
+
+
+    private function renderPlotContour($groupID)
+    {
+        $contourStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+        $seriesPlots = array();
+
+        $dataValues = array();
+        //    Loop through each data series in turn
+        for ($i = 0; $i < $seriesCount; ++$i) {
+            $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+            $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+            $dataValues[$i] = $dataValuesX;
+        }
+        $seriesPlot = new ContourPlot($dataValues);
+
+        $this->graph->Add($seriesPlot);
+    }
+
+
+    private function renderPlotStock($groupID)
+    {
+        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+        $plotOrder = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder();
+
+        $dataValues = array();
+        //    Loop through each data series in turn and build the plot arrays
+        foreach ($plotOrder as $i => $v) {
+            $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($v)->getDataValues();
+            foreach ($dataValuesX as $j => $dataValueX) {
+                $dataValues[$plotOrder[$i]][$j] = $dataValueX;
+            }
+        }
+        if (empty($dataValues)) {
+            return;
+        }
+
+        $dataValuesPlot = array();
+        // Flatten the plot arrays to a single dimensional array to work with jpgraph
+        for ($j = 0; $j < count($dataValues[0]); ++$j) {
+            for ($i = 0; $i < $seriesCount; ++$i) {
+                $dataValuesPlot[] = $dataValues[$i][$j];
+            }
+        }
+
+        // Set the x-axis labels
+        $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+        if ($labelCount > 0) {
+            $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+            $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+            $this->graph->xaxis->SetTickLabels($datasetLabels);
+        }
+
+        $seriesPlot = new StockPlot($dataValuesPlot);
+        $seriesPlot->SetWidth(20);
+
+        $this->graph->Add($seriesPlot);
+    }
+
+
+    private function renderAreaChart($groupCount, $dimensions = '2d')
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+        $this->renderCartesianPlotArea();
+
+        for ($i = 0; $i < $groupCount; ++$i) {
+            $this->renderPlotLine($i, true, false, $dimensions);
+        }
+    }
+
+
+    private function renderLineChart($groupCount, $dimensions = '2d')
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+        $this->renderCartesianPlotArea();
+
+        for ($i = 0; $i < $groupCount; ++$i) {
+            $this->renderPlotLine($i, false, false, $dimensions);
+        }
+    }
+
+
+    private function renderBarChart($groupCount, $dimensions = '2d')
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_bar.php');
+
+        $this->renderCartesianPlotArea();
+
+        for ($i = 0; $i < $groupCount; ++$i) {
+            $this->renderPlotBar($i, $dimensions);
+        }
+    }
+
+
+    private function renderScatterChart($groupCount)
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_regstat.php');
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+        $this->renderCartesianPlotArea('linlin');
+
+        for ($i = 0; $i < $groupCount; ++$i) {
+            $this->renderPlotScatter($i, false);
+        }
+    }
+
+
+    private function renderBubbleChart($groupCount)
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
+
+        $this->renderCartesianPlotArea('linlin');
+
+        for ($i = 0; $i < $groupCount; ++$i) {
+            $this->renderPlotScatter($i, true);
+        }
+    }
+
+
+    private function renderPieChart($groupCount, $dimensions = '2d', $doughnut = false, $multiplePlots = false)
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_pie.php');
+        if ($dimensions == '3d') {
+            require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_pie3d.php');
+        }
+
+        $this->renderPiePlotArea($doughnut);
+
+        $iLimit = ($multiplePlots) ? $groupCount : 1;
+        for ($groupID = 0; $groupID < $iLimit; ++$groupID) {
+            $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+            $exploded = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+            if ($groupID == 0) {
+                $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+                if ($labelCount > 0) {
+                    $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+                    $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+                }
+            }
+
+            $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+            $seriesPlots = array();
+            //    For pie charts, we only display the first series: doughnut charts generally display all series
+            $jLimit = ($multiplePlots) ? $seriesCount : 1;
+            //    Loop through each data series in turn
+            for ($j = 0; $j < $jLimit; ++$j) {
+                $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+
+                //    Fill in any missing values in the $dataValues array
+                $testCurrentIndex = 0;
+                foreach ($dataValues as $k => $dataValue) {
+                    while ($k != $testCurrentIndex) {
+                        $dataValues[$testCurrentIndex] = null;
+                        ++$testCurrentIndex;
+                    }
+                    ++$testCurrentIndex;
+                }
+
+                if ($dimensions == '3d') {
+                    $seriesPlot = new PiePlot3D($dataValues);
+                } else {
+                    if ($doughnut) {
+                        $seriesPlot = new PiePlotC($dataValues);
+                    } else {
+                        $seriesPlot = new PiePlot($dataValues);
+                    }
+                }
+
+                if ($multiplePlots) {
+                    $seriesPlot->SetSize(($jLimit-$j) / ($jLimit * 4));
+                }
+
+                if ($doughnut) {
+                    $seriesPlot->SetMidColor('white');
+                }
+
+                $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+                if (count($datasetLabels) > 0) {
+                    $seriesPlot->SetLabels(array_fill(0, count($datasetLabels), ''));
+                }
+                if ($dimensions != '3d') {
+                    $seriesPlot->SetGuideLines(false);
+                }
+                if ($j == 0) {
+                    if ($exploded) {
+                        $seriesPlot->ExplodeAll();
+                    }
+                    $seriesPlot->SetLegends($datasetLabels);
+                }
+
+                $this->graph->Add($seriesPlot);
+            }
+        }
+    }
+
+
+    private function renderRadarChart($groupCount)
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_radar.php');
+
+        $this->renderRadarPlotArea();
+
+        for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
+            $this->renderPlotRadar($groupID);
+        }
+    }
+
+
+    private function renderStockChart($groupCount)
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_stock.php');
+
+        $this->renderCartesianPlotArea('intint');
+
+        for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
+            $this->renderPlotStock($groupID);
+        }
+    }
+
+
+    private function renderContourChart($groupCount, $dimensions)
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_contour.php');
+
+        $this->renderCartesianPlotArea('intint');
+
+        for ($i = 0; $i < $groupCount; ++$i) {
+            $this->renderPlotContour($i);
+        }
+    }
+
+
+    private function renderCombinationChart($groupCount, $dimensions, $outputDestination)
+    {
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_bar.php');
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_regstat.php');
+        require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+        $this->renderCartesianPlotArea();
+
+        for ($i = 0; $i < $groupCount; ++$i) {
+            $dimensions = null;
+            $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+            switch ($chartType) {
+                case 'area3DChart':
+                    $dimensions = '3d';
+                    // no break
+                case 'areaChart':
+                    $this->renderPlotLine($i, true, true, $dimensions);
+                    break;
+                case 'bar3DChart':
+                    $dimensions = '3d';
+                    // no break
+                case 'barChart':
+                    $this->renderPlotBar($i, $dimensions);
+                    break;
+                case 'line3DChart':
+                    $dimensions = '3d';
+                    // no break
+                case 'lineChart':
+                    $this->renderPlotLine($i, false, true, $dimensions);
+                    break;
+                case 'scatterChart':
+                    $this->renderPlotScatter($i, false);
+                    break;
+                case 'bubbleChart':
+                    $this->renderPlotScatter($i, true);
+                    break;
+                default:
+                    $this->graph = null;
+                    return false;
+            }
+        }
+
+        $this->renderLegend();
+
+        $this->graph->Stroke($outputDestination);
+        return true;
+    }
+
+
+    public function render($outputDestination)
+    {
+        self::$plotColour = 0;
+
+        $groupCount = $this->chart->getPlotArea()->getPlotGroupCount();
+
+        $dimensions = null;
+        if ($groupCount == 1) {
+            $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType();
+        } else {
+            $chartTypes = array();
+            for ($i = 0; $i < $groupCount; ++$i) {
+                $chartTypes[] = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+            }
+            $chartTypes = array_unique($chartTypes);
+            if (count($chartTypes) == 1) {
+                $chartType = array_pop($chartTypes);
+            } elseif (count($chartTypes) == 0) {
+                echo 'Chart is not yet implemented<br />';
+                return false;
+            } else {
+                return $this->renderCombinationChart($groupCount, $dimensions, $outputDestination);
+            }
+        }
+
+        switch ($chartType) {
+            case 'area3DChart':
+                $dimensions = '3d';
+                // no break
+            case 'areaChart':
+                $this->renderAreaChart($groupCount, $dimensions);
+                break;
+            case 'bar3DChart':
+                $dimensions = '3d';
+                // no break
+            case 'barChart':
+                $this->renderBarChart($groupCount, $dimensions);
+                break;
+            case 'line3DChart':
+                $dimensions = '3d';
+                // no break
+            case 'lineChart':
+                $this->renderLineChart($groupCount, $dimensions);
+                break;
+            case 'pie3DChart':
+                $dimensions = '3d';
+                // no break
+            case 'pieChart':
+                $this->renderPieChart($groupCount, $dimensions, false, false);
+                break;
+            case 'doughnut3DChart':
+                $dimensions = '3d';
+                // no break
+            case 'doughnutChart':
+                $this->renderPieChart($groupCount, $dimensions, true, true);
+                break;
+            case 'scatterChart':
+                $this->renderScatterChart($groupCount);
+                break;
+            case 'bubbleChart':
+                $this->renderBubbleChart($groupCount);
+                break;
+            case 'radarChart':
+                $this->renderRadarChart($groupCount);
+                break;
+            case 'surface3DChart':
+                $dimensions = '3d';
+                // no break
+            case 'surfaceChart':
+                $this->renderContourChart($groupCount, $dimensions);
+                break;
+            case 'stockChart':
+                $this->renderStockChart($groupCount, $dimensions);
+                break;
+            default:
+                echo $chartType.' is not yet implemented<br />';
+                return false;
+        }
+        $this->renderLegend();
+
+        $this->graph->Stroke($outputDestination);
+        return true;
+    }
+
+
+    /**
+     * Create a new PHPExcel_Chart_Renderer_jpgraph
+     */
+    public function __construct(PHPExcel_Chart $chart)
+    {
+        $this->graph    = null;
+        $this->chart    = $chart;
+    }
+}

+ 86 - 0
backend/RTP/extend/excel/PHPExcel/Chart/Title.php

@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * PHPExcel_Chart_Title
+ *
+ * Copyright (c) 2006 - 2015 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_Chart
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+class PHPExcel_Chart_Title
+{
+
+    /**
+     * Title Caption
+     *
+     * @var string
+     */
+    private $caption = null;
+
+    /**
+     * Title Layout
+     *
+     * @var PHPExcel_Chart_Layout
+     */
+    private $layout = null;
+
+    /**
+     * Create a new PHPExcel_Chart_Title
+     */
+    public function __construct($caption = null, PHPExcel_Chart_Layout $layout = null)
+    {
+        $this->caption = $caption;
+        $this->layout = $layout;
+    }
+
+    /**
+     * Get caption
+     *
+     * @return string
+     */
+    public function getCaption()
+    {
+        return $this->caption;
+    }
+
+    /**
+     * Set caption
+     *
+     * @param string $caption
+     * @return PHPExcel_Chart_Title
+     */
+    public function setCaption($caption = null)
+    {
+        $this->caption = $caption;
+        
+        return $this;
+    }
+
+    /**
+     * Get Layout
+     *
+     * @return PHPExcel_Chart_Layout
+     */
+    public function getLayout()
+    {
+        return $this->layout;
+    }
+}

+ 338 - 0
backend/RTP/extend/excel/PHPExcel/Comment.php

@@ -0,0 +1,338 @@
+<?php
+
+/**
+ * PHPExcel_Comment
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Comment implements PHPExcel_IComparable
+{
+    /**
+     * Author
+     *
+     * @var string
+     */
+    private $author;
+
+    /**
+     * Rich text comment
+     *
+     * @var PHPExcel_RichText
+     */
+    private $text;
+
+    /**
+     * Comment width (CSS style, i.e. XXpx or YYpt)
+     *
+     * @var string
+     */
+    private $width = '96pt';
+
+    /**
+     * Left margin (CSS style, i.e. XXpx or YYpt)
+     *
+     * @var string
+     */
+    private $marginLeft = '59.25pt';
+
+    /**
+     * Top margin (CSS style, i.e. XXpx or YYpt)
+     *
+     * @var string
+     */
+    private $marginTop = '1.5pt';
+
+    /**
+     * Visible
+     *
+     * @var boolean
+     */
+    private $visible = false;
+
+    /**
+     * Comment height (CSS style, i.e. XXpx or YYpt)
+     *
+     * @var string
+     */
+    private $height = '55.5pt';
+
+    /**
+     * Comment fill color
+     *
+     * @var PHPExcel_Style_Color
+     */
+    private $fillColor;
+
+    /**
+     * Alignment
+     *
+     * @var string
+     */
+    private $alignment;
+
+    /**
+     * Create a new PHPExcel_Comment
+     *
+     * @throws PHPExcel_Exception
+     */
+    public function __construct()
+    {
+        // Initialise variables
+        $this->author    = 'Author';
+        $this->text      = new PHPExcel_RichText();
+        $this->fillColor = new PHPExcel_Style_Color('FFFFFFE1');
+        $this->alignment = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL;
+    }
+
+    /**
+     * Get Author
+     *
+     * @return string
+     */
+    public function getAuthor()
+    {
+        return $this->author;
+    }
+
+    /**
+     * Set Author
+     *
+     * @param string $pValue
+     * @return PHPExcel_Comment
+     */
+    public function setAuthor($pValue = '')
+    {
+        $this->author = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Rich text comment
+     *
+     * @return PHPExcel_RichText
+     */
+    public function getText()
+    {
+        return $this->text;
+    }
+
+    /**
+     * Set Rich text comment
+     *
+     * @param PHPExcel_RichText $pValue
+     * @return PHPExcel_Comment
+     */
+    public function setText(PHPExcel_RichText $pValue)
+    {
+        $this->text = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get comment width (CSS style, i.e. XXpx or YYpt)
+     *
+     * @return string
+     */
+    public function getWidth()
+    {
+        return $this->width;
+    }
+
+    /**
+     * Set comment width (CSS style, i.e. XXpx or YYpt)
+     *
+     * @param string $value
+     * @return PHPExcel_Comment
+     */
+    public function setWidth($value = '96pt')
+    {
+        $this->width = $value;
+        return $this;
+    }
+
+    /**
+     * Get comment height (CSS style, i.e. XXpx or YYpt)
+     *
+     * @return string
+     */
+    public function getHeight()
+    {
+        return $this->height;
+    }
+
+    /**
+     * Set comment height (CSS style, i.e. XXpx or YYpt)
+     *
+     * @param string $value
+     * @return PHPExcel_Comment
+     */
+    public function setHeight($value = '55.5pt')
+    {
+        $this->height = $value;
+        return $this;
+    }
+
+    /**
+     * Get left margin (CSS style, i.e. XXpx or YYpt)
+     *
+     * @return string
+     */
+    public function getMarginLeft()
+    {
+        return $this->marginLeft;
+    }
+
+    /**
+     * Set left margin (CSS style, i.e. XXpx or YYpt)
+     *
+     * @param string $value
+     * @return PHPExcel_Comment
+     */
+    public function setMarginLeft($value = '59.25pt')
+    {
+        $this->marginLeft = $value;
+        return $this;
+    }
+
+    /**
+     * Get top margin (CSS style, i.e. XXpx or YYpt)
+     *
+     * @return string
+     */
+    public function getMarginTop()
+    {
+        return $this->marginTop;
+    }
+
+    /**
+     * Set top margin (CSS style, i.e. XXpx or YYpt)
+     *
+     * @param string $value
+     * @return PHPExcel_Comment
+     */
+    public function setMarginTop($value = '1.5pt')
+    {
+        $this->marginTop = $value;
+        return $this;
+    }
+
+    /**
+     * Is the comment visible by default?
+     *
+     * @return boolean
+     */
+    public function getVisible()
+    {
+        return $this->visible;
+    }
+
+    /**
+     * Set comment default visibility
+     *
+     * @param boolean $value
+     * @return PHPExcel_Comment
+     */
+    public function setVisible($value = false)
+    {
+        $this->visible = $value;
+        return $this;
+    }
+
+    /**
+     * Get fill color
+     *
+     * @return PHPExcel_Style_Color
+     */
+    public function getFillColor()
+    {
+        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
+     *
+     * @return string    Hash code
+     */
+    public function getHashCode()
+    {
+        return md5(
+            $this->author .
+            $this->text->getHashCode() .
+            $this->width .
+            $this->height .
+            $this->marginLeft .
+            $this->marginTop .
+            ($this->visible ? 1 : 0) .
+            $this->fillColor->getHashCode() .
+            $this->alignment .
+            __CLASS__
+        );
+    }
+
+    /**
+     * 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)) {
+                $this->$key = clone $value;
+            } else {
+                $this->$key = $value;
+            }
+        }
+    }
+
+    /**
+     * Convert to string
+     *
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->text->getPlainText();
+    }
+}

+ 611 - 0
backend/RTP/extend/excel/PHPExcel/DocumentProperties.php

@@ -0,0 +1,611 @@
+<?php
+
+/**
+ * PHPExcel_DocumentProperties
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_DocumentProperties
+{
+    /** constants */
+    const PROPERTY_TYPE_BOOLEAN = 'b';
+    const PROPERTY_TYPE_INTEGER = 'i';
+    const PROPERTY_TYPE_FLOAT   = 'f';
+    const PROPERTY_TYPE_DATE    = 'd';
+    const PROPERTY_TYPE_STRING  = 's';
+    const PROPERTY_TYPE_UNKNOWN = 'u';
+
+    /**
+     * Creator
+     *
+     * @var string
+     */
+    private $creator = 'Unknown Creator';
+
+    /**
+     * LastModifiedBy
+     *
+     * @var string
+     */
+    private $lastModifiedBy;
+
+    /**
+     * Created
+     *
+     * @var datetime
+     */
+    private $created;
+
+    /**
+     * Modified
+     *
+     * @var datetime
+     */
+    private $modified;
+
+    /**
+     * Title
+     *
+     * @var string
+     */
+    private $title = 'Untitled Spreadsheet';
+
+    /**
+     * Description
+     *
+     * @var string
+     */
+    private $description = '';
+
+    /**
+     * Subject
+     *
+     * @var string
+     */
+    private $subject = '';
+
+    /**
+     * Keywords
+     *
+     * @var string
+     */
+    private $keywords = '';
+
+    /**
+     * Category
+     *
+     * @var string
+     */
+    private $category = '';
+
+    /**
+     * Manager
+     *
+     * @var string
+     */
+    private $manager = '';
+
+    /**
+     * Company
+     *
+     * @var string
+     */
+    private $company = 'Microsoft Corporation';
+
+    /**
+     * Custom Properties
+     *
+     * @var string
+     */
+    private $customProperties = array();
+
+
+    /**
+     * Create a new PHPExcel_DocumentProperties
+     */
+    public function __construct()
+    {
+        // Initialise values
+        $this->lastModifiedBy = $this->creator;
+        $this->created  = time();
+        $this->modified = time();
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Get Last Modified By
+     *
+     * @return string
+     */
+    public function getLastModifiedBy()
+    {
+        return $this->lastModifiedBy;
+    }
+
+    /**
+     * Set Last Modified By
+     *
+     * @param string $pValue
+     * @return PHPExcel_DocumentProperties
+     */
+    public function setLastModifiedBy($pValue = '')
+    {
+        $this->lastModifiedBy = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Created
+     *
+     * @return datetime
+     */
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    /**
+     * Set Created
+     *
+     * @param datetime $pValue
+     * @return PHPExcel_DocumentProperties
+     */
+    public function setCreated($pValue = null)
+    {
+        if ($pValue === null) {
+            $pValue = time();
+        } elseif (is_string($pValue)) {
+            if (is_numeric($pValue)) {
+                $pValue = intval($pValue);
+            } else {
+                $pValue = strtotime($pValue);
+            }
+        }
+
+        $this->created = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Modified
+     *
+     * @return datetime
+     */
+    public function getModified()
+    {
+        return $this->modified;
+    }
+
+    /**
+     * Set Modified
+     *
+     * @param datetime $pValue
+     * @return PHPExcel_DocumentProperties
+     */
+    public function setModified($pValue = null)
+    {
+        if ($pValue === null) {
+            $pValue = time();
+        } elseif (is_string($pValue)) {
+            if (is_numeric($pValue)) {
+                $pValue = intval($pValue);
+            } else {
+                $pValue = strtotime($pValue);
+            }
+        }
+
+        $this->modified = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Title
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * Set Title
+     *
+     * @param string $pValue
+     * @return PHPExcel_DocumentProperties
+     */
+    public function setTitle($pValue = '')
+    {
+        $this->title = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Description
+     *
+     * @return string
+     */
+    public function getDescription()
+    {
+        return $this->description;
+    }
+
+    /**
+     * Set Description
+     *
+     * @param string $pValue
+     * @return PHPExcel_DocumentProperties
+     */
+    public function setDescription($pValue = '')
+    {
+        $this->description = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Subject
+     *
+     * @return string
+     */
+    public function getSubject()
+    {
+        return $this->subject;
+    }
+
+    /**
+     * Set Subject
+     *
+     * @param string $pValue
+     * @return PHPExcel_DocumentProperties
+     */
+    public function setSubject($pValue = '')
+    {
+        $this->subject = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Keywords
+     *
+     * @return string
+     */
+    public function getKeywords()
+    {
+        return $this->keywords;
+    }
+
+    /**
+     * Set Keywords
+     *
+     * @param string $pValue
+     * @return PHPExcel_DocumentProperties
+     */
+    public function setKeywords($pValue = '')
+    {
+        $this->keywords = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get Category
+     *
+     * @return string
+     */
+    public function getCategory()
+    {
+        return $this->category;
+    }
+
+    /**
+     * 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 (($propertyType === null) || (!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 ($propertyValue === null) {
+                $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.
+     */
+    public function __clone()
+    {
+        $vars = get_object_vars($this);
+        foreach ($vars as $key => $value) {
+            if (is_object($value)) {
+                $this->$key = clone $value;
+            } else {
+                $this->$key = $value;
+            }
+        }
+    }
+
+    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;
+    }
+}

+ 222 - 0
backend/RTP/extend/excel/PHPExcel/DocumentSecurity.php

@@ -0,0 +1,222 @@
+<?php
+
+/**
+ * PHPExcel_DocumentSecurity
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_DocumentSecurity
+{
+    /**
+     * LockRevision
+     *
+     * @var boolean
+     */
+    private $lockRevision;
+
+    /**
+     * LockStructure
+     *
+     * @var boolean
+     */
+    private $lockStructure;
+
+    /**
+     * LockWindows
+     *
+     * @var boolean
+     */
+    private $lockWindows;
+
+    /**
+     * RevisionsPassword
+     *
+     * @var string
+     */
+    private $revisionsPassword;
+
+    /**
+     * WorkbookPassword
+     *
+     * @var string
+     */
+    private $workbookPassword;
+
+    /**
+     * Create a new PHPExcel_DocumentSecurity
+     */
+    public function __construct()
+    {
+        // Initialise values
+        $this->lockRevision      = false;
+        $this->lockStructure     = false;
+        $this->lockWindows       = false;
+        $this->revisionsPassword = '';
+        $this->workbookPassword  = '';
+    }
+
+    /**
+     * Is some sort of document security enabled?
+     *
+     * @return boolean
+     */
+    public function isSecurityEnabled()
+    {
+        return  $this->lockRevision ||
+                $this->lockStructure ||
+                $this->lockWindows;
+    }
+
+    /**
+     * Get LockRevision
+     *
+     * @return boolean
+     */
+    public function getLockRevision()
+    {
+        return $this->lockRevision;
+    }
+
+    /**
+     * Set LockRevision
+     *
+     * @param boolean $pValue
+     * @return PHPExcel_DocumentSecurity
+     */
+    public function setLockRevision($pValue = false)
+    {
+        $this->lockRevision = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get LockStructure
+     *
+     * @return boolean
+     */
+    public function getLockStructure()
+    {
+        return $this->lockStructure;
+    }
+
+    /**
+     * Set LockStructure
+     *
+     * @param boolean $pValue
+     * @return PHPExcel_DocumentSecurity
+     */
+    public function setLockStructure($pValue = false)
+    {
+        $this->lockStructure = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get LockWindows
+     *
+     * @return boolean
+     */
+    public function getLockWindows()
+    {
+        return $this->lockWindows;
+    }
+
+    /**
+     * Set LockWindows
+     *
+     * @param boolean $pValue
+     * @return PHPExcel_DocumentSecurity
+     */
+    public function setLockWindows($pValue = false)
+    {
+        $this->lockWindows = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get RevisionsPassword (hashed)
+     *
+     * @return string
+     */
+    public function getRevisionsPassword()
+    {
+        return $this->revisionsPassword;
+    }
+
+    /**
+     * Set RevisionsPassword
+     *
+     * @param string     $pValue
+     * @param boolean     $pAlreadyHashed If the password has already been hashed, set this to true
+     * @return PHPExcel_DocumentSecurity
+     */
+    public function setRevisionsPassword($pValue = '', $pAlreadyHashed = false)
+    {
+        if (!$pAlreadyHashed) {
+            $pValue = PHPExcel_Shared_PasswordHasher::hashPassword($pValue);
+        }
+        $this->revisionsPassword = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get WorkbookPassword (hashed)
+     *
+     * @return string
+     */
+    public function getWorkbookPassword()
+    {
+        return $this->workbookPassword;
+    }
+
+    /**
+     * Set WorkbookPassword
+     *
+     * @param string     $pValue
+     * @param boolean     $pAlreadyHashed If the password has already been hashed, set this to true
+     * @return PHPExcel_DocumentSecurity
+     */
+    public function setWorkbookPassword($pValue = '', $pAlreadyHashed = false)
+    {
+        if (!$pAlreadyHashed) {
+            $pValue = PHPExcel_Shared_PasswordHasher::hashPassword($pValue);
+        }
+        $this->workbookPassword = $pValue;
+        return $this;
+    }
+
+    /**
+     * 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)) {
+                $this->$key = clone $value;
+            } else {
+                $this->$key = $value;
+            }
+        }
+    }
+}

+ 54 - 0
backend/RTP/extend/excel/PHPExcel/Exception.php

@@ -0,0 +1,54 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+
+
+/**
+ * PHPExcel_Exception
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Exception extends Exception
+{
+    /**
+     * Error handler callback
+     *
+     * @param mixed $code
+     * @param mixed $string
+     * @param mixed $file
+     * @param mixed $line
+     * @param mixed $context
+     */
+    public static function errorHandlerCallback($code, $string, $file, $line, $context)
+    {
+        $e = new self($string, $code);
+        $e->line = $line;
+        $e->file = $file;
+        throw $e;
+    }
+}

+ 204 - 0
backend/RTP/extend/excel/PHPExcel/HashTable.php

@@ -0,0 +1,204 @@
+<?php
+
+/**
+ * PHPExcel_HashTable
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_HashTable
+{
+    /**
+     * HashTable elements
+     *
+     * @var array
+     */
+    protected $items = array();
+
+    /**
+     * HashTable key map
+     *
+     * @var array
+     */
+    protected $keyMap = array();
+
+    /**
+     * Create a new PHPExcel_HashTable
+     *
+     * @param    PHPExcel_IComparable[] $pSource    Optional source array to create HashTable from
+     * @throws    PHPExcel_Exception
+     */
+    public function __construct($pSource = null)
+    {
+        if ($pSource !== null) {
+            // Create HashTable
+            $this->addFromSource($pSource);
+        }
+    }
+
+    /**
+     * Add HashTable items from source
+     *
+     * @param    PHPExcel_IComparable[] $pSource    Source array to create HashTable from
+     * @throws    PHPExcel_Exception
+     */
+    public function addFromSource($pSource = null)
+    {
+        // Check if an array was passed
+        if ($pSource == null) {
+            return;
+        } elseif (!is_array($pSource)) {
+            throw new PHPExcel_Exception('Invalid array parameter passed.');
+        }
+
+        foreach ($pSource as $item) {
+            $this->add($item);
+        }
+    }
+
+    /**
+     * Add HashTable item
+     *
+     * @param    PHPExcel_IComparable $pSource    Item to add
+     * @throws    PHPExcel_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    PHPExcel_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;
+                }
+
+                if ($value == $hash) {
+                    $deleteKey = $key;
+                }
+            }
+            unset($this->keyMap[count($this->keyMap) - 1]);
+        }
+    }
+
+    /**
+     * Clear HashTable
+     *
+     */
+    public function clear()
+    {
+        $this->items = array();
+        $this->keyMap = array();
+    }
+
+    /**
+     * 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 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;
+    }
+
+    /**
+     * Get by hashcode
+     *
+     * @param    string    $pHashCode
+     * @return    PHPExcel_IComparable
+     *
+     */
+    public function getByHashCode($pHashCode = '')
+    {
+        if (isset($this->items[$pHashCode])) {
+            return $this->items[$pHashCode];
+        }
+
+        return null;
+    }
+
+    /**
+     * 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.
+     */
+    public function __clone()
+    {
+        $vars = get_object_vars($this);
+        foreach ($vars as $key => $value) {
+            if (is_object($value)) {
+                $this->$key = clone $value;
+            }
+        }
+    }
+}

+ 808 - 0
backend/RTP/extend/excel/PHPExcel/Helper/HTML.php

@@ -0,0 +1,808 @@
+<?php
+
+class PHPExcel_Helper_HTML
+{
+    protected static $colourMap = array(
+        'aliceblue' => 'f0f8ff',
+        'antiquewhite' => 'faebd7',
+        'antiquewhite1' => 'ffefdb',
+        'antiquewhite2' => 'eedfcc',
+        'antiquewhite3' => 'cdc0b0',
+        'antiquewhite4' => '8b8378',
+        'aqua' => '00ffff',
+        'aquamarine1' => '7fffd4',
+        'aquamarine2' => '76eec6',
+        'aquamarine4' => '458b74',
+        'azure1' => 'f0ffff',
+        'azure2' => 'e0eeee',
+        'azure3' => 'c1cdcd',
+        'azure4' => '838b8b',
+        'beige' => 'f5f5dc',
+        'bisque1' => 'ffe4c4',
+        'bisque2' => 'eed5b7',
+        'bisque3' => 'cdb79e',
+        'bisque4' => '8b7d6b',
+        'black' => '000000',
+        'blanchedalmond' => 'ffebcd',
+        'blue' => '0000ff',
+        'blue1' => '0000ff',
+        'blue2' => '0000ee',
+        'blue4' => '00008b',
+        'blueviolet' => '8a2be2',
+        'brown' => 'a52a2a',
+        'brown1' => 'ff4040',
+        'brown2' => 'ee3b3b',
+        'brown3' => 'cd3333',
+        'brown4' => '8b2323',
+        'burlywood' => 'deb887',
+        'burlywood1' => 'ffd39b',
+        'burlywood2' => 'eec591',
+        'burlywood3' => 'cdaa7d',
+        'burlywood4' => '8b7355',
+        'cadetblue' => '5f9ea0',
+        'cadetblue1' => '98f5ff',
+        'cadetblue2' => '8ee5ee',
+        'cadetblue3' => '7ac5cd',
+        'cadetblue4' => '53868b',
+        'chartreuse1' => '7fff00',
+        'chartreuse2' => '76ee00',
+        'chartreuse3' => '66cd00',
+        'chartreuse4' => '458b00',
+        'chocolate' => 'd2691e',
+        'chocolate1' => 'ff7f24',
+        'chocolate2' => 'ee7621',
+        'chocolate3' => 'cd661d',
+        'coral' => 'ff7f50',
+        'coral1' => 'ff7256',
+        'coral2' => 'ee6a50',
+        'coral3' => 'cd5b45',
+        'coral4' => '8b3e2f',
+        'cornflowerblue' => '6495ed',
+        'cornsilk1' => 'fff8dc',
+        'cornsilk2' => 'eee8cd',
+        'cornsilk3' => 'cdc8b1',
+        'cornsilk4' => '8b8878',
+        'cyan1' => '00ffff',
+        'cyan2' => '00eeee',
+        'cyan3' => '00cdcd',
+        'cyan4' => '008b8b',
+        'darkgoldenrod' => 'b8860b',
+        'darkgoldenrod1' => 'ffb90f',
+        'darkgoldenrod2' => 'eead0e',
+        'darkgoldenrod3' => 'cd950c',
+        'darkgoldenrod4' => '8b6508',
+        'darkgreen' => '006400',
+        'darkkhaki' => 'bdb76b',
+        'darkolivegreen' => '556b2f',
+        'darkolivegreen1' => 'caff70',
+        'darkolivegreen2' => 'bcee68',
+        'darkolivegreen3' => 'a2cd5a',
+        'darkolivegreen4' => '6e8b3d',
+        'darkorange' => 'ff8c00',
+        'darkorange1' => 'ff7f00',
+        'darkorange2' => 'ee7600',
+        'darkorange3' => 'cd6600',
+        'darkorange4' => '8b4500',
+        'darkorchid' => '9932cc',
+        'darkorchid1' => 'bf3eff',
+        'darkorchid2' => 'b23aee',
+        'darkorchid3' => '9a32cd',
+        'darkorchid4' => '68228b',
+        'darksalmon' => 'e9967a',
+        'darkseagreen' => '8fbc8f',
+        'darkseagreen1' => 'c1ffc1',
+        'darkseagreen2' => 'b4eeb4',
+        'darkseagreen3' => '9bcd9b',
+        'darkseagreen4' => '698b69',
+        'darkslateblue' => '483d8b',
+        'darkslategray' => '2f4f4f',
+        'darkslategray1' => '97ffff',
+        'darkslategray2' => '8deeee',
+        'darkslategray3' => '79cdcd',
+        'darkslategray4' => '528b8b',
+        'darkturquoise' => '00ced1',
+        'darkviolet' => '9400d3',
+        'deeppink1' => 'ff1493',
+        'deeppink2' => 'ee1289',
+        'deeppink3' => 'cd1076',
+        'deeppink4' => '8b0a50',
+        'deepskyblue1' => '00bfff',
+        'deepskyblue2' => '00b2ee',
+        'deepskyblue3' => '009acd',
+        'deepskyblue4' => '00688b',
+        'dimgray' => '696969',
+        'dodgerblue1' => '1e90ff',
+        'dodgerblue2' => '1c86ee',
+        'dodgerblue3' => '1874cd',
+        'dodgerblue4' => '104e8b',
+        'firebrick' => 'b22222',
+        'firebrick1' => 'ff3030',
+        'firebrick2' => 'ee2c2c',
+        'firebrick3' => 'cd2626',
+        'firebrick4' => '8b1a1a',
+        'floralwhite' => 'fffaf0',
+        'forestgreen' => '228b22',
+        'fuchsia' => 'ff00ff',
+        'gainsboro' => 'dcdcdc',
+        'ghostwhite' => 'f8f8ff',
+        'gold1' => 'ffd700',
+        'gold2' => 'eec900',
+        'gold3' => 'cdad00',
+        'gold4' => '8b7500',
+        'goldenrod' => 'daa520',
+        'goldenrod1' => 'ffc125',
+        'goldenrod2' => 'eeb422',
+        'goldenrod3' => 'cd9b1d',
+        'goldenrod4' => '8b6914',
+        'gray' => 'bebebe',
+        'gray1' => '030303',
+        'gray10' => '1a1a1a',
+        'gray11' => '1c1c1c',
+        'gray12' => '1f1f1f',
+        'gray13' => '212121',
+        'gray14' => '242424',
+        'gray15' => '262626',
+        'gray16' => '292929',
+        'gray17' => '2b2b2b',
+        'gray18' => '2e2e2e',
+        'gray19' => '303030',
+        'gray2' => '050505',
+        'gray20' => '333333',
+        'gray21' => '363636',
+        'gray22' => '383838',
+        'gray23' => '3b3b3b',
+        'gray24' => '3d3d3d',
+        'gray25' => '404040',
+        'gray26' => '424242',
+        'gray27' => '454545',
+        'gray28' => '474747',
+        'gray29' => '4a4a4a',
+        'gray3' => '080808',
+        'gray30' => '4d4d4d',
+        'gray31' => '4f4f4f',
+        'gray32' => '525252',
+        'gray33' => '545454',
+        'gray34' => '575757',
+        'gray35' => '595959',
+        'gray36' => '5c5c5c',
+        'gray37' => '5e5e5e',
+        'gray38' => '616161',
+        'gray39' => '636363',
+        'gray4' => '0a0a0a',
+        'gray40' => '666666',
+        'gray41' => '696969',
+        'gray42' => '6b6b6b',
+        'gray43' => '6e6e6e',
+        'gray44' => '707070',
+        'gray45' => '737373',
+        'gray46' => '757575',
+        'gray47' => '787878',
+        'gray48' => '7a7a7a',
+        'gray49' => '7d7d7d',
+        'gray5' => '0d0d0d',
+        'gray50' => '7f7f7f',
+        'gray51' => '828282',
+        'gray52' => '858585',
+        'gray53' => '878787',
+        'gray54' => '8a8a8a',
+        'gray55' => '8c8c8c',
+        'gray56' => '8f8f8f',
+        'gray57' => '919191',
+        'gray58' => '949494',
+        'gray59' => '969696',
+        'gray6' => '0f0f0f',
+        'gray60' => '999999',
+        'gray61' => '9c9c9c',
+        'gray62' => '9e9e9e',
+        'gray63' => 'a1a1a1',
+        'gray64' => 'a3a3a3',
+        'gray65' => 'a6a6a6',
+        'gray66' => 'a8a8a8',
+        'gray67' => 'ababab',
+        'gray68' => 'adadad',
+        'gray69' => 'b0b0b0',
+        'gray7' => '121212',
+        'gray70' => 'b3b3b3',
+        'gray71' => 'b5b5b5',
+        'gray72' => 'b8b8b8',
+        'gray73' => 'bababa',
+        'gray74' => 'bdbdbd',
+        'gray75' => 'bfbfbf',
+        'gray76' => 'c2c2c2',
+        'gray77' => 'c4c4c4',
+        'gray78' => 'c7c7c7',
+        'gray79' => 'c9c9c9',
+        'gray8' => '141414',
+        'gray80' => 'cccccc',
+        'gray81' => 'cfcfcf',
+        'gray82' => 'd1d1d1',
+        'gray83' => 'd4d4d4',
+        'gray84' => 'd6d6d6',
+        'gray85' => 'd9d9d9',
+        'gray86' => 'dbdbdb',
+        'gray87' => 'dedede',
+        'gray88' => 'e0e0e0',
+        'gray89' => 'e3e3e3',
+        'gray9' => '171717',
+        'gray90' => 'e5e5e5',
+        'gray91' => 'e8e8e8',
+        'gray92' => 'ebebeb',
+        'gray93' => 'ededed',
+        'gray94' => 'f0f0f0',
+        'gray95' => 'f2f2f2',
+        'gray97' => 'f7f7f7',
+        'gray98' => 'fafafa',
+        'gray99' => 'fcfcfc',
+        'green' => '00ff00',
+        'green1' => '00ff00',
+        'green2' => '00ee00',
+        'green3' => '00cd00',
+        'green4' => '008b00',
+        'greenyellow' => 'adff2f',
+        'honeydew1' => 'f0fff0',
+        'honeydew2' => 'e0eee0',
+        'honeydew3' => 'c1cdc1',
+        'honeydew4' => '838b83',
+        'hotpink' => 'ff69b4',
+        'hotpink1' => 'ff6eb4',
+        'hotpink2' => 'ee6aa7',
+        'hotpink3' => 'cd6090',
+        'hotpink4' => '8b3a62',
+        'indianred' => 'cd5c5c',
+        'indianred1' => 'ff6a6a',
+        'indianred2' => 'ee6363',
+        'indianred3' => 'cd5555',
+        'indianred4' => '8b3a3a',
+        'ivory1' => 'fffff0',
+        'ivory2' => 'eeeee0',
+        'ivory3' => 'cdcdc1',
+        'ivory4' => '8b8b83',
+        'khaki' => 'f0e68c',
+        'khaki1' => 'fff68f',
+        'khaki2' => 'eee685',
+        'khaki3' => 'cdc673',
+        'khaki4' => '8b864e',
+        'lavender' => 'e6e6fa',
+        'lavenderblush1' => 'fff0f5',
+        'lavenderblush2' => 'eee0e5',
+        'lavenderblush3' => 'cdc1c5',
+        'lavenderblush4' => '8b8386',
+        'lawngreen' => '7cfc00',
+        'lemonchiffon1' => 'fffacd',
+        'lemonchiffon2' => 'eee9bf',
+        'lemonchiffon3' => 'cdc9a5',
+        'lemonchiffon4' => '8b8970',
+        'light' => 'eedd82',
+        'lightblue' => 'add8e6',
+        'lightblue1' => 'bfefff',
+        'lightblue2' => 'b2dfee',
+        'lightblue3' => '9ac0cd',
+        'lightblue4' => '68838b',
+        'lightcoral' => 'f08080',
+        'lightcyan1' => 'e0ffff',
+        'lightcyan2' => 'd1eeee',
+        'lightcyan3' => 'b4cdcd',
+        'lightcyan4' => '7a8b8b',
+        'lightgoldenrod1' => 'ffec8b',
+        'lightgoldenrod2' => 'eedc82',
+        'lightgoldenrod3' => 'cdbe70',
+        'lightgoldenrod4' => '8b814c',
+        'lightgoldenrodyellow' => 'fafad2',
+        'lightgray' => 'd3d3d3',
+        'lightpink' => 'ffb6c1',
+        'lightpink1' => 'ffaeb9',
+        'lightpink2' => 'eea2ad',
+        'lightpink3' => 'cd8c95',
+        'lightpink4' => '8b5f65',
+        'lightsalmon1' => 'ffa07a',
+        'lightsalmon2' => 'ee9572',
+        'lightsalmon3' => 'cd8162',
+        'lightsalmon4' => '8b5742',
+        'lightseagreen' => '20b2aa',
+        'lightskyblue' => '87cefa',
+        'lightskyblue1' => 'b0e2ff',
+        'lightskyblue2' => 'a4d3ee',
+        'lightskyblue3' => '8db6cd',
+        'lightskyblue4' => '607b8b',
+        'lightslateblue' => '8470ff',
+        'lightslategray' => '778899',
+        'lightsteelblue' => 'b0c4de',
+        'lightsteelblue1' => 'cae1ff',
+        'lightsteelblue2' => 'bcd2ee',
+        'lightsteelblue3' => 'a2b5cd',
+        'lightsteelblue4' => '6e7b8b',
+        'lightyellow1' => 'ffffe0',
+        'lightyellow2' => 'eeeed1',
+        'lightyellow3' => 'cdcdb4',
+        'lightyellow4' => '8b8b7a',
+        'lime' => '00ff00',
+        'limegreen' => '32cd32',
+        'linen' => 'faf0e6',
+        'magenta' => 'ff00ff',
+        'magenta2' => 'ee00ee',
+        'magenta3' => 'cd00cd',
+        'magenta4' => '8b008b',
+        'maroon' => 'b03060',
+        'maroon1' => 'ff34b3',
+        'maroon2' => 'ee30a7',
+        'maroon3' => 'cd2990',
+        'maroon4' => '8b1c62',
+        'medium' => '66cdaa',
+        'mediumaquamarine' => '66cdaa',
+        'mediumblue' => '0000cd',
+        'mediumorchid' => 'ba55d3',
+        'mediumorchid1' => 'e066ff',
+        'mediumorchid2' => 'd15fee',
+        'mediumorchid3' => 'b452cd',
+        'mediumorchid4' => '7a378b',
+        'mediumpurple' => '9370db',
+        'mediumpurple1' => 'ab82ff',
+        'mediumpurple2' => '9f79ee',
+        'mediumpurple3' => '8968cd',
+        'mediumpurple4' => '5d478b',
+        'mediumseagreen' => '3cb371',
+        'mediumslateblue' => '7b68ee',
+        'mediumspringgreen' => '00fa9a',
+        'mediumturquoise' => '48d1cc',
+        'mediumvioletred' => 'c71585',
+        'midnightblue' => '191970',
+        'mintcream' => 'f5fffa',
+        'mistyrose1' => 'ffe4e1',
+        'mistyrose2' => 'eed5d2',
+        'mistyrose3' => 'cdb7b5',
+        'mistyrose4' => '8b7d7b',
+        'moccasin' => 'ffe4b5',
+        'navajowhite1' => 'ffdead',
+        'navajowhite2' => 'eecfa1',
+        'navajowhite3' => 'cdb38b',
+        'navajowhite4' => '8b795e',
+        'navy' => '000080',
+        'navyblue' => '000080',
+        'oldlace' => 'fdf5e6',
+        'olive' => '808000',
+        'olivedrab' => '6b8e23',
+        'olivedrab1' => 'c0ff3e',
+        'olivedrab2' => 'b3ee3a',
+        'olivedrab4' => '698b22',
+        'orange' => 'ffa500',
+        'orange1' => 'ffa500',
+        'orange2' => 'ee9a00',
+        'orange3' => 'cd8500',
+        'orange4' => '8b5a00',
+        'orangered1' => 'ff4500',
+        'orangered2' => 'ee4000',
+        'orangered3' => 'cd3700',
+        'orangered4' => '8b2500',
+        'orchid' => 'da70d6',
+        'orchid1' => 'ff83fa',
+        'orchid2' => 'ee7ae9',
+        'orchid3' => 'cd69c9',
+        'orchid4' => '8b4789',
+        'pale' => 'db7093',
+        'palegoldenrod' => 'eee8aa',
+        'palegreen' => '98fb98',
+        'palegreen1' => '9aff9a',
+        'palegreen2' => '90ee90',
+        'palegreen3' => '7ccd7c',
+        'palegreen4' => '548b54',
+        'paleturquoise' => 'afeeee',
+        'paleturquoise1' => 'bbffff',
+        'paleturquoise2' => 'aeeeee',
+        'paleturquoise3' => '96cdcd',
+        'paleturquoise4' => '668b8b',
+        'palevioletred' => 'db7093',
+        'palevioletred1' => 'ff82ab',
+        'palevioletred2' => 'ee799f',
+        'palevioletred3' => 'cd6889',
+        'palevioletred4' => '8b475d',
+        'papayawhip' => 'ffefd5',
+        'peachpuff1' => 'ffdab9',
+        'peachpuff2' => 'eecbad',
+        'peachpuff3' => 'cdaf95',
+        'peachpuff4' => '8b7765',
+        'pink' => 'ffc0cb',
+        'pink1' => 'ffb5c5',
+        'pink2' => 'eea9b8',
+        'pink3' => 'cd919e',
+        'pink4' => '8b636c',
+        'plum' => 'dda0dd',
+        'plum1' => 'ffbbff',
+        'plum2' => 'eeaeee',
+        'plum3' => 'cd96cd',
+        'plum4' => '8b668b',
+        'powderblue' => 'b0e0e6',
+        'purple' => 'a020f0',
+        'rebeccapurple' => '663399',
+        'purple1' => '9b30ff',
+        'purple2' => '912cee',
+        'purple3' => '7d26cd',
+        'purple4' => '551a8b',
+        'red' => 'ff0000',
+        'red1' => 'ff0000',
+        'red2' => 'ee0000',
+        'red3' => 'cd0000',
+        'red4' => '8b0000',
+        'rosybrown' => 'bc8f8f',
+        'rosybrown1' => 'ffc1c1',
+        'rosybrown2' => 'eeb4b4',
+        'rosybrown3' => 'cd9b9b',
+        'rosybrown4' => '8b6969',
+        'royalblue' => '4169e1',
+        'royalblue1' => '4876ff',
+        'royalblue2' => '436eee',
+        'royalblue3' => '3a5fcd',
+        'royalblue4' => '27408b',
+        'saddlebrown' => '8b4513',
+        'salmon' => 'fa8072',
+        'salmon1' => 'ff8c69',
+        'salmon2' => 'ee8262',
+        'salmon3' => 'cd7054',
+        'salmon4' => '8b4c39',
+        'sandybrown' => 'f4a460',
+        'seagreen1' => '54ff9f',
+        'seagreen2' => '4eee94',
+        'seagreen3' => '43cd80',
+        'seagreen4' => '2e8b57',
+        'seashell1' => 'fff5ee',
+        'seashell2' => 'eee5de',
+        'seashell3' => 'cdc5bf',
+        'seashell4' => '8b8682',
+        'sienna' => 'a0522d',
+        'sienna1' => 'ff8247',
+        'sienna2' => 'ee7942',
+        'sienna3' => 'cd6839',
+        'sienna4' => '8b4726',
+        'silver' => 'c0c0c0',
+        'skyblue' => '87ceeb',
+        'skyblue1' => '87ceff',
+        'skyblue2' => '7ec0ee',
+        'skyblue3' => '6ca6cd',
+        'skyblue4' => '4a708b',
+        'slateblue' => '6a5acd',
+        'slateblue1' => '836fff',
+        'slateblue2' => '7a67ee',
+        'slateblue3' => '6959cd',
+        'slateblue4' => '473c8b',
+        'slategray' => '708090',
+        'slategray1' => 'c6e2ff',
+        'slategray2' => 'b9d3ee',
+        'slategray3' => '9fb6cd',
+        'slategray4' => '6c7b8b',
+        'snow1' => 'fffafa',
+        'snow2' => 'eee9e9',
+        'snow3' => 'cdc9c9',
+        'snow4' => '8b8989',
+        'springgreen1' => '00ff7f',
+        'springgreen2' => '00ee76',
+        'springgreen3' => '00cd66',
+        'springgreen4' => '008b45',
+        'steelblue' => '4682b4',
+        'steelblue1' => '63b8ff',
+        'steelblue2' => '5cacee',
+        'steelblue3' => '4f94cd',
+        'steelblue4' => '36648b',
+        'tan' => 'd2b48c',
+        'tan1' => 'ffa54f',
+        'tan2' => 'ee9a49',
+        'tan3' => 'cd853f',
+        'tan4' => '8b5a2b',
+        'teal' => '008080',
+        'thistle' => 'd8bfd8',
+        'thistle1' => 'ffe1ff',
+        'thistle2' => 'eed2ee',
+        'thistle3' => 'cdb5cd',
+        'thistle4' => '8b7b8b',
+        'tomato1' => 'ff6347',
+        'tomato2' => 'ee5c42',
+        'tomato3' => 'cd4f39',
+        'tomato4' => '8b3626',
+        'turquoise' => '40e0d0',
+        'turquoise1' => '00f5ff',
+        'turquoise2' => '00e5ee',
+        'turquoise3' => '00c5cd',
+        'turquoise4' => '00868b',
+        'violet' => 'ee82ee',
+        'violetred' => 'd02090',
+        'violetred1' => 'ff3e96',
+        'violetred2' => 'ee3a8c',
+        'violetred3' => 'cd3278',
+        'violetred4' => '8b2252',
+        'wheat' => 'f5deb3',
+        'wheat1' => 'ffe7ba',
+        'wheat2' => 'eed8ae',
+        'wheat3' => 'cdba96',
+        'wheat4' => '8b7e66',
+        'white' => 'ffffff',
+        'whitesmoke' => 'f5f5f5',
+        'yellow' => 'ffff00',
+        'yellow1' => 'ffff00',
+        'yellow2' => 'eeee00',
+        'yellow3' => 'cdcd00',
+        'yellow4' => '8b8b00',
+        'yellowgreen' => '9acd32',
+    );
+
+    protected $face;
+    protected $size;
+    protected $color;
+
+    protected $bold = false;
+    protected $italic = false;
+    protected $underline = false;
+    protected $superscript = false;
+    protected $subscript = false;
+    protected $strikethrough = false;
+
+    protected $startTagCallbacks = array(
+        'font' => 'startFontTag',
+        'b' => 'startBoldTag',
+        'strong' => 'startBoldTag',
+        'i' => 'startItalicTag',
+        'em' => 'startItalicTag',
+        'u' => 'startUnderlineTag',
+        'ins' => 'startUnderlineTag',
+        'del' => 'startStrikethruTag',
+        'sup' => 'startSuperscriptTag',
+        'sub' => 'startSubscriptTag',
+    );
+
+    protected $endTagCallbacks = array(
+        'font' => 'endFontTag',
+        'b' => 'endBoldTag',
+        'strong' => 'endBoldTag',
+        'i' => 'endItalicTag',
+        'em' => 'endItalicTag',
+        'u' => 'endUnderlineTag',
+        'ins' => 'endUnderlineTag',
+        'del' => 'endStrikethruTag',
+        'sup' => 'endSuperscriptTag',
+        'sub' => 'endSubscriptTag',
+        'br' => 'breakTag',
+        'p' => 'breakTag',
+        'h1' => 'breakTag',
+        'h2' => 'breakTag',
+        'h3' => 'breakTag',
+        'h4' => 'breakTag',
+        'h5' => 'breakTag',
+        'h6' => 'breakTag',
+    );
+
+    protected $stack = array();
+
+    protected $stringData = '';
+
+    protected $richTextObject;
+
+    protected function initialise()
+    {
+        $this->face = $this->size = $this->color = null;
+        $this->bold = $this->italic = $this->underline = $this->superscript = $this->subscript = $this->strikethrough = false;
+
+        $this->stack = array();
+
+        $this->stringData = '';
+    }
+
+    public function toRichTextObject($html)
+    {
+        $this->initialise();
+
+        //  Create a new DOM object
+        $dom = new \DOMDocument;
+        //  Load the HTML file into the DOM object
+        //  Note the use of error suppression, because typically this will be an html fragment, so not fully valid markup
+        $loaded = @$dom->loadHTML($html);
+
+        //  Discard excess white space
+        $dom->preserveWhiteSpace = false;
+
+        $this->richTextObject = new PHPExcel_RichText();;
+        $this->parseElements($dom);
+
+        // Clean any further spurious whitespace
+        $this->cleanWhitespace();
+
+        return $this->richTextObject;
+    }
+
+    protected function cleanWhitespace()
+    {
+        foreach ($this->richTextObject->getRichTextElements() as $key => $element) {
+            $text = $element->getText();
+            // Trim any leading spaces on the first run
+            if ($key == 0) {
+                $text = ltrim($text);
+            }
+            // Trim any spaces immediately after a line break
+            $text = preg_replace('/\n */mu', "\n", $text);
+            $element->setText($text);
+        }
+    }
+
+    protected function buildTextRun()
+    {
+        $text = $this->stringData;
+        if (trim($text) === '') {
+            return;
+        }
+
+        $richtextRun = $this->richTextObject->createTextRun($this->stringData);
+        if ($this->face) {
+            $richtextRun->getFont()->setName($this->face);
+        }
+        if ($this->size) {
+            $richtextRun->getFont()->setSize($this->size);
+        }
+        if ($this->color) {
+            $richtextRun->getFont()->setColor(new PHPExcel_Style_Color('ff' . $this->color));
+        }
+        if ($this->bold) {
+            $richtextRun->getFont()->setBold(true);
+        }
+        if ($this->italic) {
+            $richtextRun->getFont()->setItalic(true);
+        }
+        if ($this->underline) {
+            $richtextRun->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+        }
+        if ($this->superscript) {
+            $richtextRun->getFont()->setSuperScript(true);
+        }
+        if ($this->subscript) {
+            $richtextRun->getFont()->setSubScript(true);
+        }
+        if ($this->strikethrough) {
+            $richtextRun->getFont()->setStrikethrough(true);
+        }
+        $this->stringData = '';
+    }
+
+    protected function rgbToColour($rgb)
+    {
+        preg_match_all('/\d+/', $rgb, $values);
+        foreach ($values[0] as &$value) {
+            $value = str_pad(dechex($value), 2, '0', STR_PAD_LEFT);
+        }
+        return implode($values[0]);
+    }
+
+    protected function colourNameLookup($rgb)
+    {
+        return self::$colourMap[$rgb];
+    }
+
+    protected function startFontTag($tag)
+    {
+        foreach ($tag->attributes as $attribute) {
+            $attributeName = strtolower($attribute->name);
+            $attributeValue = $attribute->value;
+
+            if ($attributeName == 'color') {
+                if (preg_match('/rgb\s*\(/', $attributeValue)) {
+                    $this->$attributeName = $this->rgbToColour($attributeValue);
+                } elseif (strpos(trim($attributeValue), '#') === 0) {
+                    $this->$attributeName = ltrim($attributeValue, '#');
+                } else {
+                    $this->$attributeName = $this->colourNameLookup($attributeValue);
+                }
+            } else {
+                $this->$attributeName = $attributeValue;
+            }
+        }
+    }
+
+    protected function endFontTag()
+    {
+        $this->face = $this->size = $this->color = null;
+    }
+
+    protected function startBoldTag()
+    {
+        $this->bold = true;
+    }
+
+    protected function endBoldTag()
+    {
+        $this->bold = false;
+    }
+
+    protected function startItalicTag()
+    {
+        $this->italic = true;
+    }
+
+    protected function endItalicTag()
+    {
+        $this->italic = false;
+    }
+
+    protected function startUnderlineTag()
+    {
+        $this->underline = true;
+    }
+
+    protected function endUnderlineTag()
+    {
+        $this->underline = false;
+    }
+
+    protected function startSubscriptTag()
+    {
+        $this->subscript = true;
+    }
+
+    protected function endSubscriptTag()
+    {
+        $this->subscript = false;
+    }
+
+    protected function startSuperscriptTag()
+    {
+        $this->superscript = true;
+    }
+
+    protected function endSuperscriptTag()
+    {
+        $this->superscript = false;
+    }
+
+    protected function startStrikethruTag()
+    {
+        $this->strikethrough = true;
+    }
+
+    protected function endStrikethruTag()
+    {
+        $this->strikethrough = false;
+    }
+
+    protected function breakTag()
+    {
+        $this->stringData .= "\n";
+    }
+
+    protected function parseTextNode(DOMText $textNode)
+    {
+        $domText = preg_replace(
+            '/\s+/u',
+            ' ',
+            str_replace(array("\r", "\n"), ' ', $textNode->nodeValue)
+        );
+        $this->stringData .= $domText;
+        $this->buildTextRun();
+    }
+
+    protected function handleCallback($element, $callbackTag, $callbacks)
+    {
+        if (isset($callbacks[$callbackTag])) {
+            $elementHandler = $callbacks[$callbackTag];
+            if (method_exists($this, $elementHandler)) {
+                call_user_func(array($this, $elementHandler), $element);
+            }
+        }
+    }
+
+    protected function parseElementNode(DOMElement $element)
+    {
+        $callbackTag = strtolower($element->nodeName);
+        $this->stack[] = $callbackTag;
+
+        $this->handleCallback($element, $callbackTag, $this->startTagCallbacks);
+
+        $this->parseElements($element);
+        array_pop($this->stack);
+
+        $this->handleCallback($element, $callbackTag, $this->endTagCallbacks);
+    }
+
+    protected function parseElements(DOMNode $element)
+    {
+        foreach ($element->childNodes as $child) {
+            if ($child instanceof DOMText) {
+                $this->parseTextNode($child);
+            } elseif ($child instanceof DOMElement) {
+                $this->parseElementNode($child);
+            }
+        }
+    }
+}

+ 34 - 0
backend/RTP/extend/excel/PHPExcel/IComparable.php

@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * PHPExcel_IComparable
+ *
+ * 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+interface PHPExcel_IComparable
+{
+    /**
+     * Get hash code
+     *
+     * @return string    Hash code
+     */
+    public function getHashCode();
+}

+ 289 - 0
backend/RTP/extend/excel/PHPExcel/IOFactory.php

@@ -0,0 +1,289 @@
+<?php
+
+/**    PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_IOFactory
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_IOFactory
+{
+    /**
+     * Search locations
+     *
+     * @var    array
+     * @access    private
+     * @static
+     */
+    private static $searchLocations = array(
+        array( 'type' => 'IWriter', 'path' => 'PHPExcel/Writer/{0}.php', 'class' => 'PHPExcel_Writer_{0}' ),
+        array( 'type' => 'IReader', 'path' => 'PHPExcel/Reader/{0}.php', 'class' => 'PHPExcel_Reader_{0}' )
+    );
+
+    /**
+     * Autoresolve classes
+     *
+     * @var    array
+     * @access    private
+     * @static
+     */
+    private static $autoResolveClasses = array(
+        'Excel2007',
+        'Excel5',
+        'Excel2003XML',
+        'OOCalc',
+        'SYLK',
+        'Gnumeric',
+        'HTML',
+        'CSV',
+    );
+
+    /**
+     *    Private constructor for PHPExcel_IOFactory
+     */
+    private function __construct()
+    {
+    }
+
+    /**
+     * Get search locations
+     *
+     * @static
+     * @access    public
+     * @return    array
+     */
+    public static function getSearchLocations()
+    {
+        return self::$searchLocations;
+    }
+
+    /**
+     * Set search locations
+     *
+     * @static
+     * @access    public
+     * @param    array $value
+     * @throws    PHPExcel_Reader_Exception
+     */
+    public static function setSearchLocations($value)
+    {
+        if (is_array($value)) {
+            self::$searchLocations = $value;
+        } else {
+            throw new PHPExcel_Reader_Exception('Invalid parameter passed.');
+        }
+    }
+
+    /**
+     * Add search location
+     *
+     * @static
+     * @access    public
+     * @param    string $type        Example: IWriter
+     * @param    string $location    Example: PHPExcel/Writer/{0}.php
+     * @param    string $classname     Example: PHPExcel_Writer_{0}
+     */
+    public static function addSearchLocation($type = '', $location = '', $classname = '')
+    {
+        self::$searchLocations[] = array( 'type' => $type, 'path' => $location, 'class' => $classname );
+    }
+
+    /**
+     * Create PHPExcel_Writer_IWriter
+     *
+     * @static
+     * @access    public
+     * @param    PHPExcel $phpExcel
+     * @param    string  $writerType    Example: Excel2007
+     * @return    PHPExcel_Writer_IWriter
+     * @throws    PHPExcel_Reader_Exception
+     */
+    public static function createWriter(PHPExcel $phpExcel, $writerType = '')
+    {
+        // Search type
+        $searchType = 'IWriter';
+
+        // Include class
+        foreach (self::$searchLocations as $searchLocation) {
+            if ($searchLocation['type'] == $searchType) {
+                $className = str_replace('{0}', $writerType, $searchLocation['class']);
+
+                $instance = new $className($phpExcel);
+                if ($instance !== null) {
+                    return $instance;
+                }
+            }
+        }
+
+        // Nothing found...
+        throw new PHPExcel_Reader_Exception("No $searchType found for type $writerType");
+    }
+
+    /**
+     * Create PHPExcel_Reader_IReader
+     *
+     * @static
+     * @access    public
+     * @param    string $readerType    Example: Excel2007
+     * @return    PHPExcel_Reader_IReader
+     * @throws    PHPExcel_Reader_Exception
+     */
+    public static function createReader($readerType = '')
+    {
+        // Search type
+        $searchType = 'IReader';
+
+        // Include class
+        foreach (self::$searchLocations as $searchLocation) {
+            if ($searchLocation['type'] == $searchType) {
+                $className = str_replace('{0}', $readerType, $searchLocation['class']);
+
+                $instance = new $className();
+                if ($instance !== null) {
+                    return $instance;
+                }
+            }
+        }
+
+        // Nothing found...
+        throw new PHPExcel_Reader_Exception("No $searchType found for type $readerType");
+    }
+
+    /**
+     * Loads PHPExcel from file using automatic PHPExcel_Reader_IReader resolution
+     *
+     * @static
+     * @access public
+     * @param     string         $pFilename        The name of the spreadsheet file
+     * @return    PHPExcel
+     * @throws    PHPExcel_Reader_Exception
+     */
+    public static function load($pFilename)
+    {
+        $reader = self::createReaderForFile($pFilename);
+        return $reader->load($pFilename);
+    }
+
+    /**
+     * Identify file type using automatic PHPExcel_Reader_IReader resolution
+     *
+     * @static
+     * @access public
+     * @param     string         $pFilename        The name of the spreadsheet file to identify
+     * @return    string
+     * @throws    PHPExcel_Reader_Exception
+     */
+    public static function identify($pFilename)
+    {
+        $reader = self::createReaderForFile($pFilename);
+        $className = get_class($reader);
+        $classType = explode('_', $className);
+        unset($reader);
+        return array_pop($classType);
+    }
+
+    /**
+     * Create PHPExcel_Reader_IReader for file using automatic PHPExcel_Reader_IReader resolution
+     *
+     * @static
+     * @access    public
+     * @param     string         $pFilename        The name of the spreadsheet file
+     * @return    PHPExcel_Reader_IReader
+     * @throws    PHPExcel_Reader_Exception
+     */
+    public static function createReaderForFile($pFilename)
+    {
+        // First, lucky guess by inspecting file extension
+        $pathinfo = pathinfo($pFilename);
+
+        $extensionType = null;
+        if (isset($pathinfo['extension'])) {
+            switch (strtolower($pathinfo['extension'])) {
+                case 'xlsx':            //    Excel (OfficeOpenXML) Spreadsheet
+                case 'xlsm':            //    Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
+                case 'xltx':            //    Excel (OfficeOpenXML) Template
+                case 'xltm':            //    Excel (OfficeOpenXML) Macro Template (macros will be discarded)
+                    $extensionType = 'Excel2007';
+                    break;
+                case 'xls':                //    Excel (BIFF) Spreadsheet
+                case 'xlt':                //    Excel (BIFF) Template
+                    $extensionType = 'Excel5';
+                    break;
+                case 'ods':                //    Open/Libre Offic Calc
+                case 'ots':                //    Open/Libre Offic Calc Template
+                    $extensionType = 'OOCalc';
+                    break;
+                case 'slk':
+                    $extensionType = 'SYLK';
+                    break;
+                case 'xml':                //    Excel 2003 SpreadSheetML
+                    $extensionType = 'Excel2003XML';
+                    break;
+                case 'gnumeric':
+                    $extensionType = 'Gnumeric';
+                    break;
+                case 'htm':
+                case 'html':
+                    $extensionType = 'HTML';
+                    break;
+                case 'csv':
+                    // Do nothing
+                    // We must not try to use CSV reader since it loads
+                    // all files including Excel files etc.
+                    break;
+                default:
+                    break;
+            }
+
+            if ($extensionType !== null) {
+                $reader = self::createReader($extensionType);
+                // Let's see if we are lucky
+                if (isset($reader) && $reader->canRead($pFilename)) {
+                    return $reader;
+                }
+            }
+        }
+
+        // If we reach here then "lucky guess" didn't give any result
+        // Try walking through all the options in self::$autoResolveClasses
+        foreach (self::$autoResolveClasses as $autoResolveClass) {
+            //    Ignore our original guess, we know that won't work
+            if ($autoResolveClass !== $extensionType) {
+                $reader = self::createReader($autoResolveClass);
+                if ($reader->canRead($pFilename)) {
+                    return $reader;
+                }
+            }
+        }
+
+        throw new PHPExcel_Reader_Exception('Unable to identify a reader for this file');
+    }
+}

+ 249 - 0
backend/RTP/extend/excel/PHPExcel/NamedRange.php

@@ -0,0 +1,249 @@
+<?php
+
+/**
+ * PHPExcel_NamedRange
+ *
+ * Copyright (c) 2006 - 2015 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
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_NamedRange
+{
+    /**
+     * Range name
+     *
+     * @var string
+     */
+    private $name;
+
+    /**
+     * Worksheet on which the named range can be resolved
+     *
+     * @var PHPExcel_Worksheet
+     */
+    private $worksheet;
+
+    /**
+     * Range of the referenced cells
+     *
+     * @var string
+     */
+    private $range;
+
+    /**
+     * Is the named range local? (i.e. can only be used on $this->worksheet)
+     *
+     * @var bool
+     */
+    private $localOnly;
+
+    /**
+     * Scope
+     *
+     * @var PHPExcel_Worksheet
+     */
+    private $scope;
+
+    /**
+     * Create a new NamedRange
+     *
+     * @param string $pName
+     * @param PHPExcel_Worksheet $pWorksheet
+     * @param string $pRange
+     * @param bool $pLocalOnly
+     * @param PHPExcel_Worksheet|null $pScope    Scope. Only applies when $pLocalOnly = true. Null for global scope.
+     * @throws PHPExcel_Exception
+     */
+    public function __construct($pName = null, PHPExcel_Worksheet $pWorksheet, $pRange = 'A1', $pLocalOnly = false, $pScope = null)
+    {
+        // Validate data
+        if (($pName === null) || ($pWorksheet === null) || ($pRange === null)) {
+            throw new PHPExcel_Exception('Parameters can not be null.');
+        }
+
+        // Set local members
+        $this->name       = $pName;
+        $this->worksheet  = $pWorksheet;
+        $this->range      = $pRange;
+        $this->localOnly  = $pLocalOnly;
+        $this->scope      = ($pLocalOnly == true) ? (($pScope == null) ? $pWorksheet : $pScope) : null;
+    }
+
+    /**
+     * Get name
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Set name
+     *
+     * @param string $value
+     * @return PHPExcel_NamedRange
+     */
+    public function setName($value = null)
+    {
+        if ($value !== null) {
+            // Old title
+            $oldTitle = $this->name;
+
+            // Re-attach
+            if ($this->worksheet !== null) {
+                $this->worksheet->getParent()->removeNamedRange($this->name, $this->worksheet);
+            }
+            $this->name = $value;
+
+            if ($this->worksheet !== null) {
+                $this->worksheet->getParent()->addNamedRange($this);
+            }
+
+            // New title
+            $newTitle = $this->name;
+            PHPExcel_ReferenceHelper::getInstance()->updateNamedFormulas($this->worksheet->getParent(), $oldTitle, $newTitle);
+        }
+        return $this;
+    }
+
+    /**
+     * Get worksheet
+     *
+     * @return PHPExcel_Worksheet
+     */
+    public function getWorksheet()
+    {
+        return $this->worksheet;
+    }
+
+    /**
+     * Set worksheet
+     *
+     * @param PHPExcel_Worksheet $value
+     * @return PHPExcel_NamedRange
+     */
+    public function setWorksheet(PHPExcel_Worksheet $value = null)
+    {
+        if ($value !== null) {
+            $this->worksheet = $value;
+        }
+        return $this;
+    }
+
+    /**
+     * Get range
+     *
+     * @return string
+     */
+    public function getRange()
+    {
+        return $this->range;
+    }
+
+    /**
+     * Set range
+     *
+     * @param string $value
+     * @return PHPExcel_NamedRange
+     */
+    public function setRange($value = null)
+    {
+        if ($value !== null) {
+            $this->range = $value;
+        }
+        return $this;
+    }
+
+    /**
+     * Get localOnly
+     *
+     * @return bool
+     */
+    public function getLocalOnly()
+    {
+        return $this->localOnly;
+    }
+
+    /**
+     * Set localOnly
+     *
+     * @param bool $value
+     * @return PHPExcel_NamedRange
+     */
+    public function setLocalOnly($value = false)
+    {
+        $this->localOnly = $value;
+        $this->scope = $value ? $this->worksheet : null;
+        return $this;
+    }
+
+    /**
+     * Get scope
+     *
+     * @return PHPExcel_Worksheet|null
+     */
+    public function getScope()
+    {
+        return $this->scope;
+    }
+
+    /**
+     * Set scope
+     *
+     * @param PHPExcel_Worksheet|null $value
+     * @return PHPExcel_NamedRange
+     */
+    public function setScope(PHPExcel_Worksheet $value = null)
+    {
+        $this->scope = $value;
+        $this->localOnly = ($value == null) ? false : true;
+        return $this;
+    }
+
+    /**
+     * Resolve a named range to a regular cell range
+     *
+     * @param string $pNamedRange Named range
+     * @param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
+     * @return PHPExcel_NamedRange
+     */
+    public static function resolveRange($pNamedRange = '', PHPExcel_Worksheet $pSheet)
+    {
+        return $pSheet->getParent()->getNamedRange($pNamedRange, $pSheet);
+    }
+
+    /**
+     * 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)) {
+                $this->$key = clone $value;
+            } else {
+                $this->$key = $value;
+            }
+        }
+    }
+}

+ 289 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Abstract.php

@@ -0,0 +1,289 @@
+<?php
+
+/**
+ * PHPExcel_Reader_Abstract
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+abstract class PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
+{
+    /**
+     * 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
+     */
+    protected $readDataOnly = false;
+
+    /**
+     * Read empty cells?
+     * Identifies whether the Reader should read data values for cells all cells, or should ignore cells containing
+     *         null value or empty string
+     *
+     * @var    boolean
+     */
+    protected $readEmptyCells = true;
+
+    /**
+     * Read charts that are defined in the workbook?
+     * Identifies whether the Reader should read the definitions for any charts that exist in the workbook;
+     *
+     * @var    boolean
+     */
+    protected $includeCharts = false;
+
+    /**
+     * 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 of string
+     */
+    protected $loadSheetsOnly;
+
+    /**
+     * PHPExcel_Reader_IReadFilter instance
+     *
+     * @var PHPExcel_Reader_IReadFilter
+     */
+    protected $readFilter;
+
+    protected $fileHandle = 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 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_IReader
+     */
+    public function setReadDataOnly($pValue = false)
+    {
+        $this->readDataOnly = $pValue;
+        return $this;
+    }
+
+    /**
+     * Read empty cells?
+     *        If this is true (the default), then the Reader will read data values for all cells, irrespective of value.
+     *        If false it will not read data for cells containing a null value or an empty string.
+     *
+     * @return    boolean
+     */
+    public function getReadEmptyCells()
+    {
+        return $this->readEmptyCells;
+    }
+
+    /**
+     * Set read empty cells
+     *        Set to true (the default) to advise the Reader read data values for all cells, irrespective of value.
+     *        Set to false to advise the Reader to ignore cells containing a null value or an empty string.
+     *
+     * @param    boolean    $pValue
+     *
+     * @return    PHPExcel_Reader_IReader
+     */
+    public function setReadEmptyCells($pValue = true)
+    {
+        $this->readEmptyCells = $pValue;
+        return $this;
+    }
+
+    /**
+     * Read charts in workbook?
+     *        If this is true, then the Reader will include any charts that exist in the workbook.
+     *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+     *        If false (the default) it will ignore any charts defined in the workbook file.
+     *
+     * @return    boolean
+     */
+    public function getIncludeCharts()
+    {
+        return $this->includeCharts;
+    }
+
+    /**
+     * Set read charts in workbook
+     *        Set to true, to advise the Reader to include any charts that exist in the workbook.
+     *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+     *        Set to false (the default) to discard charts.
+     *
+     * @param    boolean    $pValue
+     *
+     * @return    PHPExcel_Reader_IReader
+     */
+    public function setIncludeCharts($pValue = false)
+    {
+        $this->includeCharts = (boolean) $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_IReader
+     */
+    public function setLoadSheetsOnly($value = null)
+    {
+        if ($value === null) {
+            return $this->setLoadAllSheets();
+        }
+
+        $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_IReader
+     */
+    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_IReader
+     */
+    public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue)
+    {
+        $this->readFilter = $pValue;
+        return $this;
+    }
+
+    /**
+     * Open file for reading
+     *
+     * @param string $pFilename
+     * @throws    PHPExcel_Reader_Exception
+     * @return resource
+     */
+    protected function openFile($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename) || !is_readable($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        // Open file
+        $this->fileHandle = fopen($pFilename, 'r');
+        if ($this->fileHandle === false) {
+            throw new PHPExcel_Reader_Exception("Could not open file " . $pFilename . " for reading.");
+        }
+    }
+
+    /**
+     * Can the current PHPExcel_Reader_IReader read the file?
+     *
+     * @param     string         $pFilename
+     * @return boolean
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function canRead($pFilename)
+    {
+        // Check if file exists
+        try {
+            $this->openFile($pFilename);
+        } catch (Exception $e) {
+            return false;
+        }
+
+        $readable = $this->isValidFormat();
+        fclose($this->fileHandle);
+        return $readable;
+    }
+
+    /**
+     * Scan theXML for use of <!ENTITY to prevent XXE/XEE attacks
+     *
+     * @param     string         $xml
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function securityScan($xml)
+    {
+        $pattern = '/\\0?' . implode('\\0?', str_split('<!DOCTYPE')) . '\\0?/';
+        if (preg_match($pattern, $xml)) {
+            throw new PHPExcel_Reader_Exception('Detected use of ENTITY in XML, spreadsheet file load() aborted to prevent XXE/XEE attacks');
+        }
+        return $xml;
+    }
+
+    /**
+     * Scan theXML for use of <!ENTITY to prevent XXE/XEE attacks
+     *
+     * @param     string         $filestream
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function securityScanFile($filestream)
+    {
+        return $this->securityScan(file_get_contents($filestream));
+    }
+}

+ 406 - 0
backend/RTP/extend/excel/PHPExcel/Reader/CSV.php

@@ -0,0 +1,406 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_CSV
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_CSV extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
+{
+    /**
+     * Input encoding
+     *
+     * @access    private
+     * @var    string
+     */
+    private $inputEncoding = 'UTF-8';
+
+    /**
+     * Delimiter
+     *
+     * @access    private
+     * @var string
+     */
+    private $delimiter = ',';
+
+    /**
+     * Enclosure
+     *
+     * @access    private
+     * @var    string
+     */
+    private $enclosure = '"';
+
+    /**
+     * Sheet index to read
+     *
+     * @access    private
+     * @var    int
+     */
+    private $sheetIndex = 0;
+
+    /**
+     * Load rows contiguously
+     *
+     * @access    private
+     * @var    int
+     */
+    private $contiguous = false;
+
+    /**
+     * Row counter for loading rows contiguously
+     *
+     * @var    int
+     */
+    private $contiguousRow = -1;
+
+
+    /**
+     * Create a new PHPExcel_Reader_CSV
+     */
+    public function __construct()
+    {
+        $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
+    }
+
+    /**
+     * Validate that the current file is a CSV file
+     *
+     * @return boolean
+     */
+    protected function isValidFormat()
+    {
+        return true;
+    }
+
+    /**
+     * Set input encoding
+     *
+     * @param string $pValue Input encoding
+     */
+    public function setInputEncoding($pValue = 'UTF-8')
+    {
+        $this->inputEncoding = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get input encoding
+     *
+     * @return string
+     */
+    public function getInputEncoding()
+    {
+        return $this->inputEncoding;
+    }
+
+    /**
+     * Move filepointer past any BOM marker
+     *
+     */
+    protected function skipBOM()
+    {
+        rewind($this->fileHandle);
+
+        switch ($this->inputEncoding) {
+            case 'UTF-8':
+                fgets($this->fileHandle, 4) == "\xEF\xBB\xBF" ?
+                    fseek($this->fileHandle, 3) : fseek($this->fileHandle, 0);
+                break;
+            case 'UTF-16LE':
+                fgets($this->fileHandle, 3) == "\xFF\xFE" ?
+                    fseek($this->fileHandle, 2) : fseek($this->fileHandle, 0);
+                break;
+            case 'UTF-16BE':
+                fgets($this->fileHandle, 3) == "\xFE\xFF" ?
+                    fseek($this->fileHandle, 2) : fseek($this->fileHandle, 0);
+                break;
+            case 'UTF-32LE':
+                fgets($this->fileHandle, 5) == "\xFF\xFE\x00\x00" ?
+                    fseek($this->fileHandle, 4) : fseek($this->fileHandle, 0);
+                break;
+            case 'UTF-32BE':
+                fgets($this->fileHandle, 5) == "\x00\x00\xFE\xFF" ?
+                    fseek($this->fileHandle, 4) : fseek($this->fileHandle, 0);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Identify any separator that is explicitly set in the file
+     *
+     */
+    protected function checkSeparator()
+    {
+        $line = fgets($this->fileHandle);
+        if ($line === false) {
+            return;
+        }
+
+        if ((strlen(trim($line, "\r\n")) == 5) && (stripos($line, 'sep=') === 0)) {
+            $this->delimiter = substr($line, 4, 1);
+            return;
+        }
+        return $this->skipBOM();
+    }
+
+    /**
+     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+     *
+     * @param     string         $pFilename
+     * @throws    PHPExcel_Reader_Exception
+     */
+    public function listWorksheetInfo($pFilename)
+    {
+        // Open file
+        $this->openFile($pFilename);
+        if (!$this->isValidFormat()) {
+            fclose($this->fileHandle);
+            throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+        }
+        $fileHandle = $this->fileHandle;
+
+        // Skip BOM, if any
+        $this->skipBOM();
+        $this->checkSeparator();
+
+        $escapeEnclosures = array( "\\" . $this->enclosure, $this->enclosure . $this->enclosure );
+
+        $worksheetInfo = array();
+        $worksheetInfo[0]['worksheetName'] = 'Worksheet';
+        $worksheetInfo[0]['lastColumnLetter'] = 'A';
+        $worksheetInfo[0]['lastColumnIndex'] = 0;
+        $worksheetInfo[0]['totalRows'] = 0;
+        $worksheetInfo[0]['totalColumns'] = 0;
+
+        // Loop through each line of the file in turn
+        while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
+            $worksheetInfo[0]['totalRows']++;
+            $worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
+        }
+
+        $worksheetInfo[0]['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex']);
+        $worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
+
+        // Close file
+        fclose($fileHandle);
+
+        return $worksheetInfo;
+    }
+
+    /**
+     * Loads PHPExcel from file
+     *
+     * @param     string         $pFilename
+     * @return PHPExcel
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function load($pFilename)
+    {
+        // Create new PHPExcel
+        $objPHPExcel = new PHPExcel();
+
+        // Load into this instance
+        return $this->loadIntoExisting($pFilename, $objPHPExcel);
+    }
+
+    /**
+     * Loads PHPExcel from file into PHPExcel instance
+     *
+     * @param     string         $pFilename
+     * @param    PHPExcel    $objPHPExcel
+     * @return     PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+    {
+        $lineEnding = ini_get('auto_detect_line_endings');
+        ini_set('auto_detect_line_endings', true);
+
+        // Open file
+        $this->openFile($pFilename);
+        if (!$this->isValidFormat()) {
+            fclose($this->fileHandle);
+            throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+        }
+        $fileHandle = $this->fileHandle;
+
+        // Skip BOM, if any
+        $this->skipBOM();
+        $this->checkSeparator();
+
+        // Create new PHPExcel object
+        while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) {
+            $objPHPExcel->createSheet();
+        }
+        $sheet = $objPHPExcel->setActiveSheetIndex($this->sheetIndex);
+
+        $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) ? $sheet->getHighestRow(): $this->contiguousRow;
+        }
+
+        // Loop through each line of the file in turn
+        while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
+            $columnLetter = 'A';
+            foreach ($rowData as $rowDatum) {
+                if ($rowDatum != '' && $this->readFilter->readCell($columnLetter, $currentRow)) {
+                    // Unescape enclosures
+                    $rowDatum = str_replace($escapeEnclosures, $this->enclosure, $rowDatum);
+
+                    // Convert encoding if necessary
+                    if ($this->inputEncoding !== 'UTF-8') {
+                        $rowDatum = PHPExcel_Shared_String::ConvertEncoding($rowDatum, 'UTF-8', $this->inputEncoding);
+                    }
+
+                    // Set cell value
+                    $sheet->getCell($columnLetter . $currentRow)->setValue($rowDatum);
+                }
+                ++$columnLetter;
+            }
+            ++$currentRow;
+        }
+
+        // Close file
+        fclose($fileHandle);
+
+        if ($this->contiguous) {
+            $this->contiguousRow = $currentRow;
+        }
+
+        ini_set('auto_detect_line_endings', $lineEnding);
+
+        // Return
+        return $objPHPExcel;
+    }
+
+    /**
+     * Get delimiter
+     *
+     * @return string
+     */
+    public function getDelimiter()
+    {
+        return $this->delimiter;
+    }
+
+    /**
+     * Set delimiter
+     *
+     * @param    string    $pValue        Delimiter, defaults to ,
+     * @return    PHPExcel_Reader_CSV
+     */
+    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_CSV
+     */
+    public function setEnclosure($pValue = '"')
+    {
+        if ($pValue == '') {
+            $pValue = '"';
+        }
+        $this->enclosure = $pValue;
+        return $this;
+    }
+
+    /**
+     * Get sheet index
+     *
+     * @return integer
+     */
+    public function getSheetIndex()
+    {
+        return $this->sheetIndex;
+    }
+
+    /**
+     * Set sheet index
+     *
+     * @param    integer        $pValue        Sheet index
+     * @return PHPExcel_Reader_CSV
+     */
+    public function setSheetIndex($pValue = 0)
+    {
+        $this->sheetIndex = $pValue;
+        return $this;
+    }
+
+    /**
+     * Set Contiguous
+     *
+     * @param boolean $contiguous
+     */
+    public function setContiguous($contiguous = false)
+    {
+        $this->contiguous = (bool) $contiguous;
+        if (!$contiguous) {
+            $this->contiguousRow = -1;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get Contiguous
+     *
+     * @return boolean
+     */
+    public function getContiguous()
+    {
+        return $this->contiguous;
+    }
+}

+ 51 - 0
backend/RTP/extend/excel/PHPExcel/Reader/DefaultReadFilter.php

@@ -0,0 +1,51 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_DefaultReadFilter
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_DefaultReadFilter implements PHPExcel_Reader_IReadFilter
+{
+    /**
+     * Should this cell be read?
+     *
+     * @param    $column           Column address (as a string value like "A", or "IV")
+     * @param    $row              Row number
+     * @param    $worksheetName    Optional worksheet name
+     * @return   boolean
+     */
+    public function readCell($column, $row, $worksheetName = '')
+    {
+        return true;
+    }
+}

+ 801 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel2003XML.php

@@ -0,0 +1,801 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_Excel2003XML
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_Excel2003XML extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
+{
+    /**
+     * Formats
+     *
+     * @var array
+     */
+    protected $styles = array();
+
+    /**
+     * Character set used in the file
+     *
+     * @var string
+     */
+    protected $charSet = 'UTF-8';
+
+    /**
+     * Create a new PHPExcel_Reader_Excel2003XML
+     */
+    public function __construct()
+    {
+        $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
+    }
+
+
+    /**
+     * Can the current PHPExcel_Reader_IReader read the file?
+     *
+     * @param     string         $pFilename
+     * @return     boolean
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function canRead($pFilename)
+    {
+
+        //    Office                    xmlns:o="urn:schemas-microsoft-com:office:office"
+        //    Excel                    xmlns:x="urn:schemas-microsoft-com:office:excel"
+        //    XML Spreadsheet            xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
+        //    Spreadsheet component    xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet"
+        //    XML schema                 xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
+        //    XML data type            xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
+        //    MS-persist recordset    xmlns:rs="urn:schemas-microsoft-com:rowset"
+        //    Rowset                    xmlns:z="#RowsetSchema"
+        //
+
+        $signature = array(
+                '<?xml version="1.0"',
+                '<?mso-application progid="Excel.Sheet"?>'
+            );
+
+        // Open file
+        $this->openFile($pFilename);
+        $fileHandle = $this->fileHandle;
+        
+        // Read sample data (first 2 KB will do)
+        $data = fread($fileHandle, 2048);
+        fclose($fileHandle);
+
+        $valid = true;
+        foreach ($signature as $match) {
+            // every part of the signature must be present
+            if (strpos($data, $match) === false) {
+                $valid = false;
+                break;
+            }
+        }
+
+        //    Retrieve charset encoding
+        if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/um', $data, $matches)) {
+            $this->charSet = strtoupper($matches[1]);
+        }
+//        echo 'Character Set is ', $this->charSet,'<br />';
+
+        return $valid;
+    }
+
+
+    /**
+     * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+     *
+     * @param     string         $pFilename
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function listWorksheetNames($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+        if (!$this->canRead($pFilename)) {
+            throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+        }
+
+        $worksheetNames = array();
+
+        $xml = simplexml_load_string($this->securityScan(file_get_contents($pFilename)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+        $namespaces = $xml->getNamespaces(true);
+
+        $xml_ss = $xml->children($namespaces['ss']);
+        foreach ($xml_ss->Worksheet as $worksheet) {
+            $worksheet_ss = $worksheet->attributes($namespaces['ss']);
+            $worksheetNames[] = self::convertStringEncoding((string) $worksheet_ss['Name'], $this->charSet);
+        }
+
+        return $worksheetNames;
+    }
+
+
+    /**
+     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+     *
+     * @param   string     $pFilename
+     * @throws   PHPExcel_Reader_Exception
+     */
+    public function listWorksheetInfo($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        $worksheetInfo = array();
+
+        $xml = simplexml_load_string($this->securityScan(file_get_contents($pFilename)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+        $namespaces = $xml->getNamespaces(true);
+
+        $worksheetID = 1;
+        $xml_ss = $xml->children($namespaces['ss']);
+        foreach ($xml_ss->Worksheet as $worksheet) {
+            $worksheet_ss = $worksheet->attributes($namespaces['ss']);
+
+            $tmpInfo = array();
+            $tmpInfo['worksheetName'] = '';
+            $tmpInfo['lastColumnLetter'] = 'A';
+            $tmpInfo['lastColumnIndex'] = 0;
+            $tmpInfo['totalRows'] = 0;
+            $tmpInfo['totalColumns'] = 0;
+
+            if (isset($worksheet_ss['Name'])) {
+                $tmpInfo['worksheetName'] = (string) $worksheet_ss['Name'];
+            } else {
+                $tmpInfo['worksheetName'] = "Worksheet_{$worksheetID}";
+            }
+
+            if (isset($worksheet->Table->Row)) {
+                $rowIndex = 0;
+
+                foreach ($worksheet->Table->Row as $rowData) {
+                    $columnIndex = 0;
+                    $rowHasData = false;
+
+                    foreach ($rowData->Cell as $cell) {
+                        if (isset($cell->Data)) {
+                            $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
+                            $rowHasData = true;
+                        }
+
+                        ++$columnIndex;
+                    }
+
+                    ++$rowIndex;
+
+                    if ($rowHasData) {
+                        $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
+                    }
+                }
+            }
+
+            $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+            $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+            $worksheetInfo[] = $tmpInfo;
+            ++$worksheetID;
+        }
+
+        return $worksheetInfo;
+    }
+
+
+    /**
+     * Loads PHPExcel from file
+     *
+     * @param     string         $pFilename
+     * @return     PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function load($pFilename)
+    {
+        // Create new PHPExcel
+        $objPHPExcel = new PHPExcel();
+        $objPHPExcel->removeSheetByIndex(0);
+
+        // Load into this instance
+        return $this->loadIntoExisting($pFilename, $objPHPExcel);
+    }
+
+    protected static function identifyFixedStyleValue($styleList, &$styleAttributeValue)
+    {
+        $styleAttributeValue = strtolower($styleAttributeValue);
+        foreach ($styleList as $style) {
+            if ($styleAttributeValue == strtolower($style)) {
+                $styleAttributeValue = $style;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * pixel units to excel width units(units of 1/256th of a character width)
+     * @param pxs
+     * @return
+     */
+    protected static function pixel2WidthUnits($pxs)
+    {
+        $UNIT_OFFSET_MAP = array(0, 36, 73, 109, 146, 182, 219);
+
+        $widthUnits = 256 * ($pxs / 7);
+        $widthUnits += $UNIT_OFFSET_MAP[($pxs % 7)];
+        return $widthUnits;
+    }
+
+    /**
+     * excel width units(units of 1/256th of a character width) to pixel units
+     * @param widthUnits
+     * @return
+     */
+    protected static function widthUnits2Pixel($widthUnits)
+    {
+        $pixels = ($widthUnits / 256) * 7;
+        $offsetWidthUnits = $widthUnits % 256;
+        $pixels += round($offsetWidthUnits / (256 / 7));
+        return $pixels;
+    }
+
+    protected static function hex2str($hex)
+    {
+        return chr(hexdec($hex[1]));
+    }
+
+    /**
+     * Loads PHPExcel from file into PHPExcel instance
+     *
+     * @param     string         $pFilename
+     * @param    PHPExcel    $objPHPExcel
+     * @return     PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+    {
+        $fromFormats    = array('\-', '\ ');
+        $toFormats      = array('-', ' ');
+
+        $underlineStyles = array (
+            PHPExcel_Style_Font::UNDERLINE_NONE,
+            PHPExcel_Style_Font::UNDERLINE_DOUBLE,
+            PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING,
+            PHPExcel_Style_Font::UNDERLINE_SINGLE,
+            PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING
+        );
+        $verticalAlignmentStyles = array (
+            PHPExcel_Style_Alignment::VERTICAL_BOTTOM,
+            PHPExcel_Style_Alignment::VERTICAL_TOP,
+            PHPExcel_Style_Alignment::VERTICAL_CENTER,
+            PHPExcel_Style_Alignment::VERTICAL_JUSTIFY
+        );
+        $horizontalAlignmentStyles = array (
+            PHPExcel_Style_Alignment::HORIZONTAL_GENERAL,
+            PHPExcel_Style_Alignment::HORIZONTAL_LEFT,
+            PHPExcel_Style_Alignment::HORIZONTAL_RIGHT,
+            PHPExcel_Style_Alignment::HORIZONTAL_CENTER,
+            PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS,
+            PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY
+        );
+
+        $timezoneObj = new DateTimeZone('Europe/London');
+        $GMT = new DateTimeZone('UTC');
+
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        if (!$this->canRead($pFilename)) {
+            throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+        }
+
+        $xml = simplexml_load_string($this->securityScan(file_get_contents($pFilename)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+        $namespaces = $xml->getNamespaces(true);
+
+        $docProps = $objPHPExcel->getProperties();
+        if (isset($xml->DocumentProperties[0])) {
+            foreach ($xml->DocumentProperties[0] as $propertyName => $propertyValue) {
+                switch ($propertyName) {
+                    case 'Title':
+                        $docProps->setTitle(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'Subject':
+                        $docProps->setSubject(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'Author':
+                        $docProps->setCreator(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'Created':
+                        $creationDate = strtotime($propertyValue);
+                        $docProps->setCreated($creationDate);
+                        break;
+                    case 'LastAuthor':
+                        $docProps->setLastModifiedBy(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'LastSaved':
+                        $lastSaveDate = strtotime($propertyValue);
+                        $docProps->setModified($lastSaveDate);
+                        break;
+                    case 'Company':
+                        $docProps->setCompany(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'Category':
+                        $docProps->setCategory(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'Manager':
+                        $docProps->setManager(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'Keywords':
+                        $docProps->setKeywords(self::convertStringEncoding($propertyValue, $this->charSet));
+                        break;
+                    case 'Description':
+                        $docProps->setDescription(self::convertStringEncoding($propertyValue, $this->charSet));
+                        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']);
+            $styleID = (string) $style_ss['ID'];
+//            echo 'Style ID = '.$styleID.'<br />';
+            $this->styles[$styleID] = (isset($this->styles['Default'])) ? $this->styles['Default'] : array();
+            foreach ($style as $styleType => $styleData) {
+                $styleAttributes = $styleData->attributes($namespaces['ss']);
+//                echo $styleType.'<br />';
+                switch ($styleType) {
+                    case 'Alignment':
+                        foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+//                                echo $styleAttributeKey.' = '.$styleAttributeValue.'<br />';
+                            $styleAttributeValue = (string) $styleAttributeValue;
+                            switch ($styleAttributeKey) {
+                                case 'Vertical':
+                                    if (self::identifyFixedStyleValue($verticalAlignmentStyles, $styleAttributeValue)) {
+                                        $this->styles[$styleID]['alignment']['vertical'] = $styleAttributeValue;
+                                    }
+                                    break;
+                                case 'Horizontal':
+                                    if (self::identifyFixedStyleValue($horizontalAlignmentStyles, $styleAttributeValue)) {
+                                        $this->styles[$styleID]['alignment']['horizontal'] = $styleAttributeValue;
+                                    }
+                                    break;
+                                case 'WrapText':
+                                    $this->styles[$styleID]['alignment']['wrap'] = true;
+                                    break;
+                            }
+                        }
+                        break;
+                    case 'Borders':
+                        foreach ($styleData->Border as $borderStyle) {
+                            $borderAttributes = $borderStyle->attributes($namespaces['ss']);
+                            $thisBorder = array();
+                            foreach ($borderAttributes as $borderStyleKey => $borderStyleValue) {
+//                                    echo $borderStyleKey.' = '.$borderStyleValue.'<br />';
+                                switch ($borderStyleKey) {
+                                    case 'LineStyle':
+                                        $thisBorder['style'] = PHPExcel_Style_Border::BORDER_MEDIUM;
+//                                                $thisBorder['style'] = $borderStyleValue;
+                                        break;
+                                    case 'Weight':
+//                                                $thisBorder['style'] = $borderStyleValue;
+                                        break;
+                                    case 'Position':
+                                        $borderPosition = strtolower($borderStyleValue);
+                                        break;
+                                    case 'Color':
+                                        $borderColour = substr($borderStyleValue, 1);
+                                        $thisBorder['color']['rgb'] = $borderColour;
+                                        break;
+                                }
+                            }
+                            if (!empty($thisBorder)) {
+                                if (($borderPosition == 'left') || ($borderPosition == 'right') || ($borderPosition == 'top') || ($borderPosition == 'bottom')) {
+                                    $this->styles[$styleID]['borders'][$borderPosition] = $thisBorder;
+                                }
+                            }
+                        }
+                        break;
+                    case 'Font':
+                        foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+//                                echo $styleAttributeKey.' = '.$styleAttributeValue.'<br />';
+                            $styleAttributeValue = (string) $styleAttributeValue;
+                            switch ($styleAttributeKey) {
+                                case 'FontName':
+                                    $this->styles[$styleID]['font']['name'] = $styleAttributeValue;
+                                    break;
+                                case 'Size':
+                                    $this->styles[$styleID]['font']['size'] = $styleAttributeValue;
+                                    break;
+                                case 'Color':
+                                    $this->styles[$styleID]['font']['color']['rgb'] = substr($styleAttributeValue, 1);
+                                    break;
+                                case 'Bold':
+                                    $this->styles[$styleID]['font']['bold'] = true;
+                                    break;
+                                case 'Italic':
+                                    $this->styles[$styleID]['font']['italic'] = true;
+                                    break;
+                                case 'Underline':
+                                    if (self::identifyFixedStyleValue($underlineStyles, $styleAttributeValue)) {
+                                        $this->styles[$styleID]['font']['underline'] = $styleAttributeValue;
+                                    }
+                                    break;
+                            }
+                        }
+                        break;
+                    case 'Interior':
+                        foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+//                                echo $styleAttributeKey.' = '.$styleAttributeValue.'<br />';
+                            switch ($styleAttributeKey) {
+                                case 'Color':
+                                    $this->styles[$styleID]['fill']['color']['rgb'] = substr($styleAttributeValue, 1);
+                                    break;
+                            }
+                        }
+                        break;
+                    case 'NumberFormat':
+                        foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+//                                echo $styleAttributeKey.' = '.$styleAttributeValue.'<br />';
+                            $styleAttributeValue = str_replace($fromFormats, $toFormats, $styleAttributeValue);
+                            switch ($styleAttributeValue) {
+                                case 'Short Date':
+                                    $styleAttributeValue = 'dd/mm/yyyy';
+                                    break;
+                            }
+                            if ($styleAttributeValue > '') {
+                                $this->styles[$styleID]['numberformat']['code'] = $styleAttributeValue;
+                            }
+                        }
+                        break;
+                    case 'Protection':
+                        foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+//                                echo $styleAttributeKey.' = '.$styleAttributeValue.'<br />';
+                        }
+                        break;
+                }
+            }
+//            print_r($this->styles[$styleID]);
+//            echo '<hr />';
+        }
+//        echo '<hr />';
+
+        $worksheetID = 0;
+        $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 '<h3>Worksheet: ', $worksheet_ss['Name'],'<h3>';
+//
+            // Create new Worksheet
+            $objPHPExcel->createSheet();
+            $objPHPExcel->setActiveSheetIndex($worksheetID);
+            if (isset($worksheet_ss['Name'])) {
+                $worksheetName = self::convertStringEncoding((string) $worksheet_ss['Name'], $this->charSet);
+                //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
+                //        formula cells... during the load, all formulae should be correct, and we're simply bringing
+                //        the worksheet name in line with the formula, not the reverse
+                $objPHPExcel->getActiveSheet()->setTitle($worksheetName, false);
+            }
+
+            $columnID = 'A';
+            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);
+                    }
+                    if (isset($columnData_ss['Width'])) {
+                        $columnWidth = $columnData_ss['Width'];
+//                        echo '<b>Setting column width for '.$columnID.' to '.$columnWidth.'</b><br />';
+                        $objPHPExcel->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4);
+                    }
+                    ++$columnID;
+                }
+            }
+
+            $rowID = 1;
+            if (isset($worksheet->Table->Row)) {
+                $additionalMergedCells = 0;
+                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 '<b>Row '.$rowID.'</b><br />';
+
+                    $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 ($this->getReadFilter() !== null) {
+                            if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
+                                continue;
+                            }
+                        }
+
+                        if ((isset($cell_ss['MergeAcross'])) || (isset($cell_ss['MergeDown']))) {
+                            $columnTo = $columnID;
+                            if (isset($cell_ss['MergeAcross'])) {
+                                $additionalMergedCells += (int)$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."<br />";
+                            }
+                            $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            = 'null';
+                                    const TYPE_INLINE        = 'inlineStr';
+                                    const TYPE_ERROR        = 'e';
+                                    */
+                                    case 'String':
+                                        $cellValue = self::convertStringEncoding($cellValue, $this->charSet);
+                                        $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<br />';
+                                $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
+                                $columnNumber = PHPExcel_Cell::columnIndexFromString($columnID);
+                                if (substr($cellDataFormula, 0, 3) == 'of:') {
+                                    $cellDataFormula = substr($cellDataFormula, 3);
+//                                    echo 'Before: ', $cellDataFormula,'<br />';
+                                    $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,'<br />';
+                                    $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,'<br />';
+                            }
+
+//                            echo 'Cell '.$columnID.$rowID.' is a '.$type.' with a value of '.(($hasCalculatedValue) ? $cellDataFormula : $cellValue).'<br />';
+//
+                            $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $cellValue), $type);
+                            if ($hasCalculatedValue) {
+//                                echo 'Formula result is '.$cellValue.'<br />';
+                                $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($cellValue);
+                            }
+                            $cellIsSet = $rowHasData = true;
+                        }
+
+                        if (isset($cell->Comment)) {
+//                            echo '<b>comment found</b><br />';
+                            $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
+                            $author = 'unknown';
+                            if (isset($commentAttributes->Author)) {
+                                $author = (string)$commentAttributes->Author;
+//                                echo 'Author: ', $author,'<br />';
+                            }
+                            $node = $cell->Comment->Data->asXML();
+//                            $annotation = str_replace('html:','',substr($node,49,-10));
+//                            echo $annotation,'<br />';
+                            $annotation = strip_tags($node);
+//                            echo 'Annotation: ', $annotation,'<br />';
+                            $objPHPExcel->getActiveSheet()->getComment($columnID.$rowID)->setAuthor(self::convertStringEncoding($author, $this->charSet))->setText($this->parseRichText($annotation));
+                        }
+
+                        if (($cellIsSet) && (isset($cell_ss['StyleID']))) {
+                            $style = (string) $cell_ss['StyleID'];
+//                            echo 'Cell style for '.$columnID.$rowID.' is '.$style.'<br />';
+                            if ((isset($this->styles[$style])) && (!empty($this->styles[$style]))) {
+//                                echo 'Cell '.$columnID.$rowID.'<br />';
+//                                print_r($this->styles[$style]);
+//                                echo '<br />';
+                                if (!$objPHPExcel->getActiveSheet()->cellExists($columnID.$rowID)) {
+                                    $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValue(null);
+                                }
+                                $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($this->styles[$style]);
+                            }
+                        }
+                        ++$columnID;
+                        while ($additionalMergedCells > 0) {
+                            ++$columnID;
+                            $additionalMergedCells--;
+                        }
+                    }
+
+                    if ($rowHasData) {
+                        if (isset($row_ss['StyleID'])) {
+                            $rowStyle = $row_ss['StyleID'];
+                        }
+                        if (isset($row_ss['Height'])) {
+                            $rowHeight = $row_ss['Height'];
+//                            echo '<b>Setting row height to '.$rowHeight.'</b><br />';
+                            $objPHPExcel->getActiveSheet()->getRowDimension($rowID)->setRowHeight($rowHeight);
+                        }
+                    }
+
+                    ++$rowID;
+                }
+            }
+            ++$worksheetID;
+        }
+
+        // Return
+        return $objPHPExcel;
+    }
+
+
+    protected static function convertStringEncoding($string, $charset)
+    {
+        if ($charset != 'UTF-8') {
+            return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $charset);
+        }
+        return $string;
+    }
+
+
+    protected function parseRichText($is = '')
+    {
+        $value = new PHPExcel_RichText();
+
+        $value->createText(self::convertStringEncoding($is, $this->charSet));
+
+        return $value;
+    }
+}

File diff suppressed because it is too large
+ 2051 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel2007.php


+ 520 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel2007/Chart.php

@@ -0,0 +1,520 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2015 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_Reader_Excel2007
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version        ##VERSION##, ##DATE##
+ */
+
+/**
+ * PHPExcel_Reader_Excel2007_Chart
+ *
+ * @category    PHPExcel
+ * @package        PHPExcel_Reader_Excel2007
+ * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Reader_Excel2007_Chart
+{
+    private static function getAttribute($component, $name, $format)
+    {
+        $attributes = $component->attributes();
+        if (isset($attributes[$name])) {
+            if ($format == 'string') {
+                return (string) $attributes[$name];
+            } elseif ($format == 'integer') {
+                return (integer) $attributes[$name];
+            } elseif ($format == 'boolean') {
+                return (boolean) ($attributes[$name] === '0' || $attributes[$name] !== 'true') ? false : true;
+            } else {
+                return (float) $attributes[$name];
+            }
+        }
+        return null;
+    }
+
+
+    private static function readColor($color, $background = false)
+    {
+        if (isset($color["rgb"])) {
+            return (string)$color["rgb"];
+        } elseif (isset($color["indexed"])) {
+            return PHPExcel_Style_Color::indexedColor($color["indexed"]-7, $background)->getARGB();
+        }
+    }
+
+    public static function readChart($chartElements, $chartName)
+    {
+        $namespacesChartMeta = $chartElements->getNamespaces(true);
+        $chartElementsC = $chartElements->children($namespacesChartMeta['c']);
+
+        $XaxisLabel = $YaxisLabel = $legend = $title = null;
+        $dispBlanksAs = $plotVisOnly = null;
+
+        foreach ($chartElementsC as $chartElementKey => $chartElement) {
+            switch ($chartElementKey) {
+                case "chart":
+                    foreach ($chartElement as $chartDetailsKey => $chartDetails) {
+                        $chartDetailsC = $chartDetails->children($namespacesChartMeta['c']);
+                        switch ($chartDetailsKey) {
+                            case "plotArea":
+                                $plotAreaLayout = $XaxisLable = $YaxisLable = null;
+                                $plotSeries = $plotAttributes = array();
+                                foreach ($chartDetails as $chartDetailKey => $chartDetail) {
+                                    switch ($chartDetailKey) {
+                                        case "layout":
+                                            $plotAreaLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta, 'plotArea');
+                                            break;
+                                        case "catAx":
+                                            if (isset($chartDetail->title)) {
+                                                $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
+                                            }
+                                            break;
+                                        case "dateAx":
+                                            if (isset($chartDetail->title)) {
+                                                $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
+                                            }
+                                            break;
+                                        case "valAx":
+                                            if (isset($chartDetail->title)) {
+                                                $YaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
+                                            }
+                                            break;
+                                        case "barChart":
+                                        case "bar3DChart":
+                                            $barDirection = self::getAttribute($chartDetail->barDir, 'val', 'string');
+                                            $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotSer->setPlotDirection($barDirection);
+                                            $plotSeries[] = $plotSer;
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "lineChart":
+                                        case "line3DChart":
+                                            $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "areaChart":
+                                        case "area3DChart":
+                                            $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "doughnutChart":
+                                        case "pieChart":
+                                        case "pie3DChart":
+                                            $explosion = isset($chartDetail->ser->explosion);
+                                            $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotSer->setPlotStyle($explosion);
+                                            $plotSeries[] = $plotSer;
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "scatterChart":
+                                            $scatterStyle = self::getAttribute($chartDetail->scatterStyle, 'val', 'string');
+                                            $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotSer->setPlotStyle($scatterStyle);
+                                            $plotSeries[] = $plotSer;
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "bubbleChart":
+                                            $bubbleScale = self::getAttribute($chartDetail->bubbleScale, 'val', 'integer');
+                                            $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotSer->setPlotStyle($bubbleScale);
+                                            $plotSeries[] = $plotSer;
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "radarChart":
+                                            $radarStyle = self::getAttribute($chartDetail->radarStyle, 'val', 'string');
+                                            $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotSer->setPlotStyle($radarStyle);
+                                            $plotSeries[] = $plotSer;
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "surfaceChart":
+                                        case "surface3DChart":
+                                            $wireFrame = self::getAttribute($chartDetail->wireframe, 'val', 'boolean');
+                                            $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotSer->setPlotStyle($wireFrame);
+                                            $plotSeries[] = $plotSer;
+                                            $plotAttributes = self::readChartAttributes($chartDetail);
+                                            break;
+                                        case "stockChart":
+                                            $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+                                            $plotAttributes = self::readChartAttributes($plotAreaLayout);
+                                            break;
+                                    }
+                                }
+                                if ($plotAreaLayout == null) {
+                                    $plotAreaLayout = new PHPExcel_Chart_Layout();
+                                }
+                                $plotArea = new PHPExcel_Chart_PlotArea($plotAreaLayout, $plotSeries);
+                                self::setChartAttributes($plotAreaLayout, $plotAttributes);
+                                break;
+                            case "plotVisOnly":
+                                $plotVisOnly = self::getAttribute($chartDetails, 'val', 'string');
+                                break;
+                            case "dispBlanksAs":
+                                $dispBlanksAs = self::getAttribute($chartDetails, 'val', 'string');
+                                break;
+                            case "title":
+                                $title = self::chartTitle($chartDetails, $namespacesChartMeta, 'title');
+                                break;
+                            case "legend":
+                                $legendPos = 'r';
+                                $legendLayout = null;
+                                $legendOverlay = false;
+                                foreach ($chartDetails as $chartDetailKey => $chartDetail) {
+                                    switch ($chartDetailKey) {
+                                        case "legendPos":
+                                            $legendPos = self::getAttribute($chartDetail, 'val', 'string');
+                                            break;
+                                        case "overlay":
+                                            $legendOverlay = self::getAttribute($chartDetail, 'val', 'boolean');
+                                            break;
+                                        case "layout":
+                                            $legendLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta, 'legend');
+                                            break;
+                                    }
+                                }
+                                $legend = new PHPExcel_Chart_Legend($legendPos, $legendLayout, $legendOverlay);
+                                break;
+                        }
+                    }
+            }
+        }
+        $chart = new PHPExcel_Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, $dispBlanksAs, $XaxisLabel, $YaxisLabel);
+
+        return $chart;
+    }
+
+    private static function chartTitle($titleDetails, $namespacesChartMeta, $type)
+    {
+        $caption = array();
+        $titleLayout = null;
+        foreach ($titleDetails as $titleDetailKey => $chartDetail) {
+            switch ($titleDetailKey) {
+                case "tx":
+                    $titleDetails = $chartDetail->rich->children($namespacesChartMeta['a']);
+                    foreach ($titleDetails as $titleKey => $titleDetail) {
+                        switch ($titleKey) {
+                            case "p":
+                                $titleDetailPart = $titleDetail->children($namespacesChartMeta['a']);
+                                $caption[] = self::parseRichText($titleDetailPart);
+                        }
+                    }
+                    break;
+                case "layout":
+                    $titleLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta);
+                    break;
+            }
+        }
+
+        return new PHPExcel_Chart_Title($caption, $titleLayout);
+    }
+
+    private static function chartLayoutDetails($chartDetail, $namespacesChartMeta)
+    {
+        if (!isset($chartDetail->manualLayout)) {
+            return null;
+        }
+        $details = $chartDetail->manualLayout->children($namespacesChartMeta['c']);
+        if (is_null($details)) {
+            return null;
+        }
+        $layout = array();
+        foreach ($details as $detailKey => $detail) {
+//            echo $detailKey, ' => ',self::getAttribute($detail, 'val', 'string'),PHP_EOL;
+            $layout[$detailKey] = self::getAttribute($detail, 'val', 'string');
+        }
+        return new PHPExcel_Chart_Layout($layout);
+    }
+
+    private static function chartDataSeries($chartDetail, $namespacesChartMeta, $plotType)
+    {
+        $multiSeriesType = null;
+        $smoothLine = false;
+        $seriesLabel = $seriesCategory = $seriesValues = $plotOrder = array();
+
+        $seriesDetailSet = $chartDetail->children($namespacesChartMeta['c']);
+        foreach ($seriesDetailSet as $seriesDetailKey => $seriesDetails) {
+            switch ($seriesDetailKey) {
+                case "grouping":
+                    $multiSeriesType = self::getAttribute($chartDetail->grouping, 'val', 'string');
+                    break;
+                case "ser":
+                    $marker = null;
+                    foreach ($seriesDetails as $seriesKey => $seriesDetail) {
+                        switch ($seriesKey) {
+                            case "idx":
+                                $seriesIndex = self::getAttribute($seriesDetail, 'val', 'integer');
+                                break;
+                            case "order":
+                                $seriesOrder = self::getAttribute($seriesDetail, 'val', 'integer');
+                                $plotOrder[$seriesIndex] = $seriesOrder;
+                                break;
+                            case "tx":
+                                $seriesLabel[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
+                                break;
+                            case "marker":
+                                $marker = self::getAttribute($seriesDetail->symbol, 'val', 'string');
+                                break;
+                            case "smooth":
+                                $smoothLine = self::getAttribute($seriesDetail, 'val', 'boolean');
+                                break;
+                            case "cat":
+                                $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
+                                break;
+                            case "val":
+                                $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
+                                break;
+                            case "xVal":
+                                $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
+                                break;
+                            case "yVal":
+                                $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
+                                break;
+                        }
+                    }
+            }
+        }
+        return new PHPExcel_Chart_DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $smoothLine);
+    }
+
+
+    private static function chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker = null, $smoothLine = false)
+    {
+        if (isset($seriesDetail->strRef)) {
+            $seriesSource = (string) $seriesDetail->strRef->f;
+            $seriesData = self::chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']), 's');
+
+            return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+        } elseif (isset($seriesDetail->numRef)) {
+            $seriesSource = (string) $seriesDetail->numRef->f;
+            $seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c']));
+
+            return new PHPExcel_Chart_DataSeriesValues('Number', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+        } elseif (isset($seriesDetail->multiLvlStrRef)) {
+            $seriesSource = (string) $seriesDetail->multiLvlStrRef->f;
+            $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']), 's');
+            $seriesData['pointCount'] = count($seriesData['dataValues']);
+
+            return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+        } elseif (isset($seriesDetail->multiLvlNumRef)) {
+            $seriesSource = (string) $seriesDetail->multiLvlNumRef->f;
+            $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']), 's');
+            $seriesData['pointCount'] = count($seriesData['dataValues']);
+
+            return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+        }
+        return null;
+    }
+
+
+    private static function chartDataSeriesValues($seriesValueSet, $dataType = 'n')
+    {
+        $seriesVal = array();
+        $formatCode = '';
+        $pointCount = 0;
+
+        foreach ($seriesValueSet as $seriesValueIdx => $seriesValue) {
+            switch ($seriesValueIdx) {
+                case 'ptCount':
+                    $pointCount = self::getAttribute($seriesValue, 'val', 'integer');
+                    break;
+                case 'formatCode':
+                    $formatCode = (string) $seriesValue;
+                    break;
+                case 'pt':
+                    $pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
+                    if ($dataType == 's') {
+                        $seriesVal[$pointVal] = (string) $seriesValue->v;
+                    } else {
+                        $seriesVal[$pointVal] = (float) $seriesValue->v;
+                    }
+                    break;
+            }
+        }
+
+        return array(
+            'formatCode'    => $formatCode,
+            'pointCount'    => $pointCount,
+            'dataValues'    => $seriesVal
+        );
+    }
+
+    private static function chartDataSeriesValuesMultiLevel($seriesValueSet, $dataType = 'n')
+    {
+        $seriesVal = array();
+        $formatCode = '';
+        $pointCount = 0;
+
+        foreach ($seriesValueSet->lvl as $seriesLevelIdx => $seriesLevel) {
+            foreach ($seriesLevel as $seriesValueIdx => $seriesValue) {
+                switch ($seriesValueIdx) {
+                    case 'ptCount':
+                        $pointCount = self::getAttribute($seriesValue, 'val', 'integer');
+                        break;
+                    case 'formatCode':
+                        $formatCode = (string) $seriesValue;
+                        break;
+                    case 'pt':
+                        $pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
+                        if ($dataType == 's') {
+                            $seriesVal[$pointVal][] = (string) $seriesValue->v;
+                        } else {
+                            $seriesVal[$pointVal][] = (float) $seriesValue->v;
+                        }
+                        break;
+                }
+            }
+        }
+
+        return array(
+            'formatCode'    => $formatCode,
+            'pointCount'    => $pointCount,
+            'dataValues'    => $seriesVal
+        );
+    }
+
+    private static function parseRichText($titleDetailPart = null)
+    {
+        $value = new PHPExcel_RichText();
+
+        foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
+            if (isset($titleDetailElement->t)) {
+                $objText = $value->createTextRun((string) $titleDetailElement->t);
+            }
+            if (isset($titleDetailElement->rPr)) {
+                if (isset($titleDetailElement->rPr->rFont["val"])) {
+                    $objText->getFont()->setName((string) $titleDetailElement->rPr->rFont["val"]);
+                }
+
+                $fontSize = (self::getAttribute($titleDetailElement->rPr, 'sz', 'integer'));
+                if (!is_null($fontSize)) {
+                    $objText->getFont()->setSize(floor($fontSize / 100));
+                }
+
+                $fontColor = (self::getAttribute($titleDetailElement->rPr, 'color', 'string'));
+                if (!is_null($fontColor)) {
+                    $objText->getFont()->setColor(new PHPExcel_Style_Color(self::readColor($fontColor)));
+                }
+
+                $bold = self::getAttribute($titleDetailElement->rPr, 'b', 'boolean');
+                if (!is_null($bold)) {
+                    $objText->getFont()->setBold($bold);
+                }
+
+                $italic = self::getAttribute($titleDetailElement->rPr, 'i', 'boolean');
+                if (!is_null($italic)) {
+                    $objText->getFont()->setItalic($italic);
+                }
+
+                $baseline = self::getAttribute($titleDetailElement->rPr, 'baseline', 'integer');
+                if (!is_null($baseline)) {
+                    if ($baseline > 0) {
+                        $objText->getFont()->setSuperScript(true);
+                    } elseif ($baseline < 0) {
+                        $objText->getFont()->setSubScript(true);
+                    }
+                }
+
+                $underscore = (self::getAttribute($titleDetailElement->rPr, 'u', 'string'));
+                if (!is_null($underscore)) {
+                    if ($underscore == 'sng') {
+                        $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+                    } elseif ($underscore == 'dbl') {
+                        $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
+                    } else {
+                        $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_NONE);
+                    }
+                }
+
+                $strikethrough = (self::getAttribute($titleDetailElement->rPr, 's', 'string'));
+                if (!is_null($strikethrough)) {
+                    if ($strikethrough == 'noStrike') {
+                        $objText->getFont()->setStrikethrough(false);
+                    } else {
+                        $objText->getFont()->setStrikethrough(true);
+                    }
+                }
+            }
+        }
+
+        return $value;
+    }
+
+    private static function readChartAttributes($chartDetail)
+    {
+        $plotAttributes = array();
+        if (isset($chartDetail->dLbls)) {
+            if (isset($chartDetail->dLbls->howLegendKey)) {
+                $plotAttributes['showLegendKey'] = self::getAttribute($chartDetail->dLbls->showLegendKey, 'val', 'string');
+            }
+            if (isset($chartDetail->dLbls->showVal)) {
+                $plotAttributes['showVal'] = self::getAttribute($chartDetail->dLbls->showVal, 'val', 'string');
+            }
+            if (isset($chartDetail->dLbls->showCatName)) {
+                $plotAttributes['showCatName'] = self::getAttribute($chartDetail->dLbls->showCatName, 'val', 'string');
+            }
+            if (isset($chartDetail->dLbls->showSerName)) {
+                $plotAttributes['showSerName'] = self::getAttribute($chartDetail->dLbls->showSerName, 'val', 'string');
+            }
+            if (isset($chartDetail->dLbls->showPercent)) {
+                $plotAttributes['showPercent'] = self::getAttribute($chartDetail->dLbls->showPercent, 'val', 'string');
+            }
+            if (isset($chartDetail->dLbls->showBubbleSize)) {
+                $plotAttributes['showBubbleSize'] = self::getAttribute($chartDetail->dLbls->showBubbleSize, 'val', 'string');
+            }
+            if (isset($chartDetail->dLbls->showLeaderLines)) {
+                $plotAttributes['showLeaderLines'] = self::getAttribute($chartDetail->dLbls->showLeaderLines, 'val', 'string');
+            }
+        }
+
+        return $plotAttributes;
+    }
+
+    private static function setChartAttributes($plotArea, $plotAttributes)
+    {
+        foreach ($plotAttributes as $plotAttributeKey => $plotAttributeValue) {
+            switch ($plotAttributeKey) {
+                case 'showLegendKey':
+                    $plotArea->setShowLegendKey($plotAttributeValue);
+                    break;
+                case 'showVal':
+                    $plotArea->setShowVal($plotAttributeValue);
+                    break;
+                case 'showCatName':
+                    $plotArea->setShowCatName($plotAttributeValue);
+                    break;
+                case 'showSerName':
+                    $plotArea->setShowSerName($plotAttributeValue);
+                    break;
+                case 'showPercent':
+                    $plotArea->setShowPercent($plotAttributeValue);
+                    break;
+                case 'showBubbleSize':
+                    $plotArea->setShowBubbleSize($plotAttributeValue);
+                    break;
+                case 'showLeaderLines':
+                    $plotArea->setShowLeaderLines($plotAttributeValue);
+                    break;
+            }
+        }
+    }
+}

+ 127 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel2007/Theme.php

@@ -0,0 +1,127 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2015 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_Reader_Excel2007
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+
+
+/**
+ * PHPExcel_Reader_Excel2007_Theme
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Reader_Excel2007
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Reader_Excel2007_Theme
+{
+    /**
+     * Theme Name
+     *
+     * @var string
+     */
+    private $themeName;
+
+    /**
+     * Colour Scheme Name
+     *
+     * @var string
+     */
+    private $colourSchemeName;
+
+    /**
+     * Colour Map indexed by position
+     *
+     * @var array of string
+     */
+    private $colourMapValues;
+
+
+    /**
+     * Colour Map
+     *
+     * @var array of string
+     */
+    private $colourMap;
+
+
+    /**
+     * Create a new PHPExcel_Theme
+     *
+     */
+    public function __construct($themeName, $colourSchemeName, $colourMap)
+    {
+        // Initialise values
+        $this->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;
+            }
+        }
+    }
+}

File diff suppressed because it is too large
+ 7594 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5.php


+ 32 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color.php

@@ -0,0 +1,32 @@
+<?php
+
+class PHPExcel_Reader_Excel5_Color
+{
+    /**
+     * Read color
+     *
+     * @param int $color Indexed color
+     * @param array $palette Color palette
+     * @return array RGB color value, example: array('rgb' => 'FF0000')
+     */
+    public static function map($color, $palette, $version)
+    {
+        if ($color <= 0x07 || $color >= 0x40) {
+            // special built-in color
+            return PHPExcel_Reader_Excel5_Color_BuiltIn::lookup($color);
+        } elseif (isset($palette) && isset($palette[$color - 8])) {
+            // palette color, color index 0x08 maps to pallete index 0
+            return $palette[$color - 8];
+        } else {
+            // default color table
+            if ($version == PHPExcel_Reader_Excel5::XLS_BIFF8) {
+                return PHPExcel_Reader_Excel5_Color_BIFF8::lookup($color);
+            } else {
+                // BIFF5
+                return PHPExcel_Reader_Excel5_Color_BIFF5::lookup($color);
+            }
+        }
+
+        return $color;
+    }
+}

+ 77 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color/BIFF5.php

@@ -0,0 +1,77 @@
+<?php
+
+class PHPExcel_Reader_Excel5_Color_BIFF5
+{
+    protected static $map = array(
+        0x08 => '000000',
+        0x09 => 'FFFFFF',
+        0x0A => 'FF0000',
+        0x0B => '00FF00',
+        0x0C => '0000FF',
+        0x0D => 'FFFF00',
+        0x0E => 'FF00FF',
+        0x0F => '00FFFF',
+        0x10 => '800000',
+        0x11 => '008000',
+        0x12 => '000080',
+        0x13 => '808000',
+        0x14 => '800080',
+        0x15 => '008080',
+        0x16 => 'C0C0C0',
+        0x17 => '808080',
+        0x18 => '8080FF',
+        0x19 => '802060',
+        0x1A => 'FFFFC0',
+        0x1B => 'A0E0F0',
+        0x1C => '600080',
+        0x1D => 'FF8080',
+        0x1E => '0080C0',
+        0x1F => 'C0C0FF',
+        0x20 => '000080',
+        0x21 => 'FF00FF',
+        0x22 => 'FFFF00',
+        0x23 => '00FFFF',
+        0x24 => '800080',
+        0x25 => '800000',
+        0x26 => '008080',
+        0x27 => '0000FF',
+        0x28 => '00CFFF',
+        0x29 => '69FFFF',
+        0x2A => 'E0FFE0',
+        0x2B => 'FFFF80',
+        0x2C => 'A6CAF0',
+        0x2D => 'DD9CB3',
+        0x2E => 'B38FEE',
+        0x2F => 'E3E3E3',
+        0x30 => '2A6FF9',
+        0x31 => '3FB8CD',
+        0x32 => '488436',
+        0x33 => '958C41',
+        0x34 => '8E5E42',
+        0x35 => 'A0627A',
+        0x36 => '624FAC',
+        0x37 => '969696',
+        0x38 => '1D2FBE',
+        0x39 => '286676',
+        0x3A => '004500',
+        0x3B => '453E01',
+        0x3C => '6A2813',
+        0x3D => '85396A',
+        0x3E => '4A3285',
+        0x3F => '424242',
+    );
+
+    /**
+     * Map color array from BIFF5 built-in color index
+     *
+     * @param int $color
+     * @return array
+     */
+    public static function lookup($color)
+    {
+        if (isset(self::$map[$color])) {
+            return array('rgb' => self::$map[$color]);
+        }
+        return array('rgb' => '000000');
+    }
+}

+ 77 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color/BIFF8.php

@@ -0,0 +1,77 @@
+<?php
+
+class PHPExcel_Reader_Excel5_Color_BIFF8
+{
+    protected static $map = array(
+        0x08 => '000000',
+        0x09 => 'FFFFFF',
+        0x0A => 'FF0000',
+        0x0B => '00FF00',
+        0x0C => '0000FF',
+        0x0D => 'FFFF00',
+        0x0E => 'FF00FF',
+        0x0F => '00FFFF',
+        0x10 => '800000',
+        0x11 => '008000',
+        0x12 => '000080',
+        0x13 => '808000',
+        0x14 => '800080',
+        0x15 => '008080',
+        0x16 => 'C0C0C0',
+        0x17 => '808080',
+        0x18 => '9999FF',
+        0x19 => '993366',
+        0x1A => 'FFFFCC',
+        0x1B => 'CCFFFF',
+        0x1C => '660066',
+        0x1D => 'FF8080',
+        0x1E => '0066CC',
+        0x1F => 'CCCCFF',
+        0x20 => '000080',
+        0x21 => 'FF00FF',
+        0x22 => 'FFFF00',
+        0x23 => '00FFFF',
+        0x24 => '800080',
+        0x25 => '800000',
+        0x26 => '008080',
+        0x27 => '0000FF',
+        0x28 => '00CCFF',
+        0x29 => 'CCFFFF',
+        0x2A => 'CCFFCC',
+        0x2B => 'FFFF99',
+        0x2C => '99CCFF',
+        0x2D => 'FF99CC',
+        0x2E => 'CC99FF',
+        0x2F => 'FFCC99',
+        0x30 => '3366FF',
+        0x31 => '33CCCC',
+        0x32 => '99CC00',
+        0x33 => 'FFCC00',
+        0x34 => 'FF9900',
+        0x35 => 'FF6600',
+        0x36 => '666699',
+        0x37 => '969696',
+        0x38 => '003366',
+        0x39 => '339966',
+        0x3A => '003300',
+        0x3B => '333300',
+        0x3C => '993300',
+        0x3D => '993366',
+        0x3E => '333399',
+        0x3F => '333333',
+    );
+
+   /**
+     * Map color array from BIFF8 built-in color index
+     *
+     * @param int $color
+     * @return array
+     */
+    public static function lookup($color)
+    {
+        if (isset(self::$map[$color])) {
+            return array('rgb' => self::$map[$color]);
+        }
+        return array('rgb' => '000000');
+    }
+}

+ 31 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Color/BuiltIn.php

@@ -0,0 +1,31 @@
+<?php
+
+class PHPExcel_Reader_Excel5_Color_BuiltIn
+{
+    protected static $map = array(
+        0x00 => '000000',
+        0x01 => 'FFFFFF',
+        0x02 => 'FF0000',
+        0x03 => '00FF00',
+        0x04 => '0000FF',
+        0x05 => 'FFFF00',
+        0x06 => 'FF00FF',
+        0x07 => '00FFFF',
+        0x40 => '000000', // system window text color
+        0x41 => 'FFFFFF', // system window background color
+    );
+
+    /**
+     * Map built-in color to RGB value
+     *
+     * @param int $color Indexed color
+     * @return array
+     */
+    public static function lookup($color)
+    {
+        if (isset(self::$map[$color])) {
+            return array('rgb' => self::$map[$color]);
+        }
+        return array('rgb' => '000000');
+    }
+}

+ 28 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/ErrorCode.php

@@ -0,0 +1,28 @@
+<?php
+
+class PHPExcel_Reader_Excel5_ErrorCode
+{
+    protected static $map = array(
+        0x00 => '#NULL!',
+        0x07 => '#DIV/0!',
+        0x0F => '#VALUE!',
+        0x17 => '#REF!',
+        0x1D => '#NAME?',
+        0x24 => '#NUM!',
+        0x2A => '#N/A',
+    );
+
+    /**
+     * Map error code, e.g. '#N/A'
+     *
+     * @param int $code
+     * @return string
+     */
+    public static function lookup($code)
+    {
+        if (isset(self::$map[$code])) {
+            return self::$map[$code];
+        }
+        return false;
+    }
+}

+ 669 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Escher.php

@@ -0,0 +1,669 @@
+<?php
+
+/**
+ * PHPExcel_Reader_Excel5_Escher
+ *
+ * Copyright (c) 2006 - 2015 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_Reader_Excel5
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_Excel5_Escher
+{
+    const DGGCONTAINER      = 0xF000;
+    const BSTORECONTAINER   = 0xF001;
+    const DGCONTAINER       = 0xF002;
+    const SPGRCONTAINER     = 0xF003;
+    const SPCONTAINER       = 0xF004;
+    const DGG               = 0xF006;
+    const BSE               = 0xF007;
+    const DG                = 0xF008;
+    const SPGR              = 0xF009;
+    const SP                = 0xF00A;
+    const OPT               = 0xF00B;
+    const CLIENTTEXTBOX     = 0xF00D;
+    const CLIENTANCHOR      = 0xF010;
+    const CLIENTDATA        = 0xF011;
+    const BLIPJPEG          = 0xF01D;
+    const BLIPPNG           = 0xF01E;
+    const SPLITMENUCOLORS   = 0xF11E;
+    const TERTIARYOPT       = 0xF122;
+
+    /**
+     * Escher stream data (binary)
+     *
+     * @var string
+     */
+    private $data;
+
+    /**
+     * Size in bytes of the Escher stream data
+     *
+     * @var int
+     */
+    private $dataSize;
+
+    /**
+     * Current position of stream pointer in Escher stream data
+     *
+     * @var int
+     */
+    private $pos;
+
+    /**
+     * The object to be returned by the reader. Modified during load.
+     *
+     * @var mixed
+     */
+    private $object;
+
+    /**
+     * Create a new PHPExcel_Reader_Excel5_Escher instance
+     *
+     * @param mixed $object
+     */
+    public function __construct($object)
+    {
+        $this->object = $object;
+    }
+
+    /**
+     * Load Escher stream data. May be a partial Escher stream.
+     *
+     * @param string $data
+     */
+    public function load($data)
+    {
+        $this->data = $data;
+
+        // total byte size of Excel data (workbook global substream + sheet substreams)
+        $this->dataSize = strlen($this->data);
+
+        $this->pos = 0;
+
+        // Parse Escher stream
+        while ($this->pos < $this->dataSize) {
+            // offset: 2; size: 2: Record Type
+            $fbt = PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos + 2);
+
+            switch ($fbt) {
+                case self::DGGCONTAINER:
+                    $this->readDggContainer();
+                    break;
+                case self::DGG:
+                    $this->readDgg();
+                    break;
+                case self::BSTORECONTAINER:
+                    $this->readBstoreContainer();
+                    break;
+                case self::BSE:
+                    $this->readBSE();
+                    break;
+                case self::BLIPJPEG:
+                    $this->readBlipJPEG();
+                    break;
+                case self::BLIPPNG:
+                    $this->readBlipPNG();
+                    break;
+                case self::OPT:
+                    $this->readOPT();
+                    break;
+                case self::TERTIARYOPT:
+                    $this->readTertiaryOPT();
+                    break;
+                case self::SPLITMENUCOLORS:
+                    $this->readSplitMenuColors();
+                    break;
+                case self::DGCONTAINER:
+                    $this->readDgContainer();
+                    break;
+                case self::DG:
+                    $this->readDg();
+                    break;
+                case self::SPGRCONTAINER:
+                    $this->readSpgrContainer();
+                    break;
+                case self::SPCONTAINER:
+                    $this->readSpContainer();
+                    break;
+                case self::SPGR:
+                    $this->readSpgr();
+                    break;
+                case self::SP:
+                    $this->readSp();
+                    break;
+                case self::CLIENTTEXTBOX:
+                    $this->readClientTextbox();
+                    break;
+                case self::CLIENTANCHOR:
+                    $this->readClientAnchor();
+                    break;
+                case self::CLIENTDATA:
+                    $this->readClientData();
+                    break;
+                default:
+                    $this->readDefault();
+                    break;
+            }
+        }
+
+        return $this->object;
+    }
+
+    /**
+     * Read a generic record
+     */
+    private function readDefault()
+    {
+        // offset 0; size: 2; recVer and recInstance
+        $verInstance = PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos);
+
+        // offset: 2; size: 2: Record Type
+        $fbt = PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos + 2);
+
+        // bit: 0-3; mask: 0x000F; recVer
+        $recVer = (0x000F & $verInstance) >> 0;
+
+        $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;
+    }
+
+    /**
+     * Read DggContainer record (Drawing Group Container)
+     */
+    private function readDggContainer()
+    {
+        $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;
+
+        // record is a container, read contents
+        $dggContainer = new PHPExcel_Shared_Escher_DggContainer();
+        $this->object->setDggContainer($dggContainer);
+        $reader = new PHPExcel_Reader_Excel5_Escher($dggContainer);
+        $reader->load($recordData);
+    }
+
+    /**
+     * Read Dgg record (Drawing Group)
+     */
+    private function readDgg()
+    {
+        $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;
+    }
+
+    /**
+     * Read BstoreContainer record (Blip Store Container)
+     */
+    private function readBstoreContainer()
+    {
+        $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;
+
+        // record is a container, read contents
+        $bstoreContainer = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer();
+        $this->object->setBstoreContainer($bstoreContainer);
+        $reader = new PHPExcel_Reader_Excel5_Escher($bstoreContainer);
+        $reader->load($recordData);
+    }
+
+    /**
+     * Read BSE record
+     */
+    private function readBSE()
+    {
+        // offset: 0; size: 2; recVer and recInstance
+
+        // bit: 4-15; mask: 0xFFF0; recInstance
+        $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($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;
+
+        // add BSE to BstoreContainer
+        $BSE = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE();
+        $this->object->addBSE($BSE);
+
+        $BSE->setBLIPType($recInstance);
+
+        // offset: 0; size: 1; btWin32 (MSOBLIPTYPE)
+        $btWin32 = ord($recordData[0]);
+
+        // offset: 1; size: 1; btWin32 (MSOBLIPTYPE)
+        $btMacOS = ord($recordData[1]);
+
+        // offset: 2; size: 16; MD4 digest
+        $rgbUid = substr($recordData, 2, 16);
+
+        // offset: 18; size: 2; tag
+        $tag = PHPExcel_Reader_Excel5::getInt2d($recordData, 18);
+
+        // offset: 20; size: 4; size of BLIP in bytes
+        $size = PHPExcel_Reader_Excel5::getInt4d($recordData, 20);
+
+        // offset: 24; size: 4; number of references to this BLIP
+        $cRef = PHPExcel_Reader_Excel5::getInt4d($recordData, 24);
+
+        // offset: 28; size: 4; MSOFO file offset
+        $foDelay = PHPExcel_Reader_Excel5::getInt4d($recordData, 28);
+
+        // offset: 32; size: 1; unused1
+        $unused1 = ord($recordData{32});
+
+        // offset: 33; size: 1; size of nameData in bytes (including null terminator)
+        $cbName = ord($recordData{33});
+
+        // offset: 34; size: 1; unused2
+        $unused2 = ord($recordData{34});
+
+        // offset: 35; size: 1; unused3
+        $unused3 = ord($recordData{35});
+
+        // offset: 36; size: $cbName; nameData
+        $nameData = substr($recordData, 36, $cbName);
+
+        // offset: 36 + $cbName, size: var; the BLIP data
+        $blipData = substr($recordData, 36 + $cbName);
+
+        // record is a container, read contents
+        $reader = new PHPExcel_Reader_Excel5_Escher($BSE);
+        $reader->load($blipData);
+    }
+
+    /**
+     * Read BlipJPEG record. Holds raw JPEG image data
+     */
+    private function readBlipJPEG()
+    {
+        // offset: 0; size: 2; recVer and recInstance
+
+        // bit: 4-15; mask: 0xFFF0; recInstance
+        $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($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;
+
+        $pos = 0;
+
+        // offset: 0; size: 16; rgbUid1 (MD4 digest of)
+        $rgbUid1 = substr($recordData, 0, 16);
+        $pos += 16;
+
+        // offset: 16; size: 16; rgbUid2 (MD4 digest), only if $recInstance = 0x46B or 0x6E3
+        if (in_array($recInstance, array(0x046B, 0x06E3))) {
+            $rgbUid2 = substr($recordData, 16, 16);
+            $pos += 16;
+        }
+
+        // offset: var; size: 1; tag
+        $tag = ord($recordData{$pos});
+        $pos += 1;
+
+        // offset: var; size: var; the raw image data
+        $data = substr($recordData, $pos);
+
+        $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
+        $blip->setData($data);
+
+        $this->object->setBlip($blip);
+    }
+
+    /**
+     * Read BlipPNG record. Holds raw PNG image data
+     */
+    private function readBlipPNG()
+    {
+        // offset: 0; size: 2; recVer and recInstance
+
+        // bit: 4-15; mask: 0xFFF0; recInstance
+        $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($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;
+
+        $pos = 0;
+
+        // offset: 0; size: 16; rgbUid1 (MD4 digest of)
+        $rgbUid1 = substr($recordData, 0, 16);
+        $pos += 16;
+
+        // offset: 16; size: 16; rgbUid2 (MD4 digest), only if $recInstance = 0x46B or 0x6E3
+        if ($recInstance == 0x06E1) {
+            $rgbUid2 = substr($recordData, 16, 16);
+            $pos += 16;
+        }
+
+        // offset: var; size: 1; tag
+        $tag = ord($recordData{$pos});
+        $pos += 1;
+
+        // offset: var; size: var; the raw image data
+        $data = substr($recordData, $pos);
+
+        $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
+        $blip->setData($data);
+
+        $this->object->setBlip($blip);
+    }
+
+    /**
+     * Read OPT record. This record may occur within DggContainer record or SpContainer
+     */
+    private function readOPT()
+    {
+        // offset: 0; size: 2; recVer and recInstance
+
+        // bit: 4-15; mask: 0xFFF0; recInstance
+        $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($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;
+
+        $this->readOfficeArtRGFOPTE($recordData, $recInstance);
+    }
+
+    /**
+     * Read TertiaryOPT record
+     */
+    private function readTertiaryOPT()
+    {
+        // offset: 0; size: 2; recVer and recInstance
+
+        // bit: 4-15; mask: 0xFFF0; recInstance
+        $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($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;
+    }
+
+    /**
+     * Read SplitMenuColors record
+     */
+    private function readSplitMenuColors()
+    {
+        $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;
+    }
+
+    /**
+     * Read DgContainer record (Drawing Container)
+     */
+    private function readDgContainer()
+    {
+        $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;
+
+        // record is a container, read contents
+        $dgContainer = new PHPExcel_Shared_Escher_DgContainer();
+        $this->object->setDgContainer($dgContainer);
+        $reader = new PHPExcel_Reader_Excel5_Escher($dgContainer);
+        $escher = $reader->load($recordData);
+    }
+
+    /**
+     * Read Dg record (Drawing)
+     */
+    private function readDg()
+    {
+        $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;
+    }
+
+    /**
+     * Read SpgrContainer record (Shape Group Container)
+     */
+    private function readSpgrContainer()
+    {
+        // context is either context DgContainer or SpgrContainer
+
+        $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;
+
+        // record is a container, read contents
+        $spgrContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer();
+
+        if ($this->object instanceof PHPExcel_Shared_Escher_DgContainer) {
+            // DgContainer
+            $this->object->setSpgrContainer($spgrContainer);
+        } else {
+            // SpgrContainer
+            $this->object->addChild($spgrContainer);
+        }
+
+        $reader = new PHPExcel_Reader_Excel5_Escher($spgrContainer);
+        $escher = $reader->load($recordData);
+    }
+
+    /**
+     * Read SpContainer record (Shape Container)
+     */
+    private function readSpContainer()
+    {
+        $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+        $recordData = substr($this->data, $this->pos + 8, $length);
+
+        // add spContainer to spgrContainer
+        $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
+        $this->object->addChild($spContainer);
+
+        // move stream pointer to next record
+        $this->pos += 8 + $length;
+
+        // record is a container, read contents
+        $reader = new PHPExcel_Reader_Excel5_Escher($spContainer);
+        $escher = $reader->load($recordData);
+    }
+
+    /**
+     * Read Spgr record (Shape Group)
+     */
+    private function readSpgr()
+    {
+        $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;
+    }
+
+    /**
+     * Read Sp record (Shape)
+     */
+    private function readSp()
+    {
+        // offset: 0; size: 2; recVer and recInstance
+
+        // bit: 4-15; mask: 0xFFF0; recInstance
+        $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($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;
+    }
+
+    /**
+     * Read ClientTextbox record
+     */
+    private function readClientTextbox()
+    {
+        // offset: 0; size: 2; recVer and recInstance
+
+        // bit: 4-15; mask: 0xFFF0; recInstance
+        $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($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;
+    }
+
+    /**
+     * Read ClientAnchor record. This record holds information about where the shape is anchored in worksheet
+     */
+    private function readClientAnchor()
+    {
+        $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 = PHPExcel_Reader_Excel5::getInt2d($recordData, 2);
+
+        // offset: 4; size: 2; upper-left corner horizontal offset in 1/1024 of column width
+        $startOffsetX = PHPExcel_Reader_Excel5::getInt2d($recordData, 4);
+
+        // offset: 6; size: 2; upper-left corner row index (0-based)
+        $r1 = PHPExcel_Reader_Excel5::getInt2d($recordData, 6);
+
+        // offset: 8; size: 2; upper-left corner vertical offset in 1/256 of row height
+        $startOffsetY = PHPExcel_Reader_Excel5::getInt2d($recordData, 8);
+
+        // offset: 10; size: 2; bottom-right corner column index (0-based)
+        $c2 = PHPExcel_Reader_Excel5::getInt2d($recordData, 10);
+
+        // offset: 12; size: 2; bottom-right corner horizontal offset in 1/1024 of column width
+        $endOffsetX = PHPExcel_Reader_Excel5::getInt2d($recordData, 12);
+
+        // offset: 14; size: 2; bottom-right corner row index (0-based)
+        $r2 = PHPExcel_Reader_Excel5::getInt2d($recordData, 14);
+
+        // offset: 16; size: 2; bottom-right corner vertical offset in 1/256 of row height
+        $endOffsetY = PHPExcel_Reader_Excel5::getInt2d($recordData, 16);
+
+        // set the start coordinates
+        $this->object->setStartCoordinates(PHPExcel_Cell::stringFromColumnIndex($c1) . ($r1 + 1));
+
+        // set the start offsetX
+        $this->object->setStartOffsetX($startOffsetX);
+
+        // set the start offsetY
+        $this->object->setStartOffsetY($startOffsetY);
+
+        // set the end coordinates
+        $this->object->setEndCoordinates(PHPExcel_Cell::stringFromColumnIndex($c2) . ($r2 + 1));
+
+        // set the end offsetX
+        $this->object->setEndOffsetX($endOffsetX);
+
+        // set the end offsetY
+        $this->object->setEndOffsetY($endOffsetY);
+    }
+
+    /**
+     * Read ClientData record
+     */
+    private function readClientData()
+    {
+        $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;
+    }
+
+    /**
+     * Read OfficeArtRGFOPTE table of property-value pairs
+     *
+     * @param string $data Binary data
+     * @param int $n Number of properties
+     */
+    private function readOfficeArtRGFOPTE($data, $n)
+    {
+        $splicedComplexData = substr($data, 6 * $n);
+
+        // loop through property-value pairs
+        for ($i = 0; $i < $n; ++$i) {
+            // read 6 bytes at a time
+            $fopte = substr($data, 6 * $i, 6);
+
+            // offset: 0; size: 2; opid
+            $opid = PHPExcel_Reader_Excel5::getInt2d($fopte, 0);
+
+            // bit: 0-13; mask: 0x3FFF; opid.opid
+            $opidOpid = (0x3FFF & $opid) >> 0;
+
+            // bit: 14; mask 0x4000; 1 = value in op field is BLIP identifier
+            $opidFBid = (0x4000 & $opid) >> 14;
+
+            // bit: 15; mask 0x8000; 1 = this is a complex property, op field specifies size of complex data
+            $opidFComplex = (0x8000 & $opid) >> 15;
+
+            // offset: 2; size: 4; the value for this property
+            $op = PHPExcel_Reader_Excel5::getInt4d($fopte, 2);
+
+            if ($opidFComplex) {
+                $complexData = substr($splicedComplexData, 0, $op);
+                $splicedComplexData = substr($splicedComplexData, $op);
+
+                // we store string value with complex data
+                $value = $complexData;
+            } else {
+                // we store integer value
+                $value = $op;
+            }
+
+            $this->object->setOPT($opidOpid, $value);
+        }
+    }
+}

+ 203 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/MD5.php

@@ -0,0 +1,203 @@
+<?php
+
+/**
+ * PHPExcel_Reader_Excel5_MD5
+ *
+ * Copyright (c) 2006 - 2015 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_Reader_Excel5
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt        LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_Excel5_MD5
+{
+    // Context
+    private $a;
+    private $b;
+    private $c;
+    private $d;
+
+    /**
+     * MD5 stream constructor
+     */
+    public function __construct()
+    {
+        $this->reset();
+    }
+
+    /**
+     * Reset the MD5 stream context
+     */
+    public function reset()
+    {
+        $this->a = 0x67452301;
+        $this->b = 0xEFCDAB89;
+        $this->c = 0x98BADCFE;
+        $this->d = 0x10325476;
+    }
+
+    /**
+     * Get MD5 stream context
+     *
+     * @return string
+     */
+    public function getContext()
+    {
+        $s = '';
+        foreach (array('a', 'b', 'c', 'd') as $i) {
+            $v = $this->{$i};
+            $s .= chr($v & 0xff);
+            $s .= chr(($v >> 8) & 0xff);
+            $s .= chr(($v >> 16) & 0xff);
+            $s .= chr(($v >> 24) & 0xff);
+        }
+
+        return $s;
+    }
+
+    /**
+     * Add data to context
+     *
+     * @param string $data Data to add
+     */
+    public function add($data)
+    {
+        $words = array_values(unpack('V16', $data));
+
+        $A = $this->a;
+        $B = $this->b;
+        $C = $this->c;
+        $D = $this->d;
+
+        $F = array('PHPExcel_Reader_Excel5_MD5','f');
+        $G = array('PHPExcel_Reader_Excel5_MD5','g');
+        $H = array('PHPExcel_Reader_Excel5_MD5','h');
+        $I = array('PHPExcel_Reader_Excel5_MD5','i');
+
+        /* ROUND 1 */
+        self::step($F, $A, $B, $C, $D, $words[0], 7, 0xd76aa478);
+        self::step($F, $D, $A, $B, $C, $words[1], 12, 0xe8c7b756);
+        self::step($F, $C, $D, $A, $B, $words[2], 17, 0x242070db);
+        self::step($F, $B, $C, $D, $A, $words[3], 22, 0xc1bdceee);
+        self::step($F, $A, $B, $C, $D, $words[4], 7, 0xf57c0faf);
+        self::step($F, $D, $A, $B, $C, $words[5], 12, 0x4787c62a);
+        self::step($F, $C, $D, $A, $B, $words[6], 17, 0xa8304613);
+        self::step($F, $B, $C, $D, $A, $words[7], 22, 0xfd469501);
+        self::step($F, $A, $B, $C, $D, $words[8], 7, 0x698098d8);
+        self::step($F, $D, $A, $B, $C, $words[9], 12, 0x8b44f7af);
+        self::step($F, $C, $D, $A, $B, $words[10], 17, 0xffff5bb1);
+        self::step($F, $B, $C, $D, $A, $words[11], 22, 0x895cd7be);
+        self::step($F, $A, $B, $C, $D, $words[12], 7, 0x6b901122);
+        self::step($F, $D, $A, $B, $C, $words[13], 12, 0xfd987193);
+        self::step($F, $C, $D, $A, $B, $words[14], 17, 0xa679438e);
+        self::step($F, $B, $C, $D, $A, $words[15], 22, 0x49b40821);
+
+        /* ROUND 2 */
+        self::step($G, $A, $B, $C, $D, $words[1], 5, 0xf61e2562);
+        self::step($G, $D, $A, $B, $C, $words[6], 9, 0xc040b340);
+        self::step($G, $C, $D, $A, $B, $words[11], 14, 0x265e5a51);
+        self::step($G, $B, $C, $D, $A, $words[0], 20, 0xe9b6c7aa);
+        self::step($G, $A, $B, $C, $D, $words[5], 5, 0xd62f105d);
+        self::step($G, $D, $A, $B, $C, $words[10], 9, 0x02441453);
+        self::step($G, $C, $D, $A, $B, $words[15], 14, 0xd8a1e681);
+        self::step($G, $B, $C, $D, $A, $words[4], 20, 0xe7d3fbc8);
+        self::step($G, $A, $B, $C, $D, $words[9], 5, 0x21e1cde6);
+        self::step($G, $D, $A, $B, $C, $words[14], 9, 0xc33707d6);
+        self::step($G, $C, $D, $A, $B, $words[3], 14, 0xf4d50d87);
+        self::step($G, $B, $C, $D, $A, $words[8], 20, 0x455a14ed);
+        self::step($G, $A, $B, $C, $D, $words[13], 5, 0xa9e3e905);
+        self::step($G, $D, $A, $B, $C, $words[2], 9, 0xfcefa3f8);
+        self::step($G, $C, $D, $A, $B, $words[7], 14, 0x676f02d9);
+        self::step($G, $B, $C, $D, $A, $words[12], 20, 0x8d2a4c8a);
+
+        /* ROUND 3 */
+        self::step($H, $A, $B, $C, $D, $words[5], 4, 0xfffa3942);
+        self::step($H, $D, $A, $B, $C, $words[8], 11, 0x8771f681);
+        self::step($H, $C, $D, $A, $B, $words[11], 16, 0x6d9d6122);
+        self::step($H, $B, $C, $D, $A, $words[14], 23, 0xfde5380c);
+        self::step($H, $A, $B, $C, $D, $words[1], 4, 0xa4beea44);
+        self::step($H, $D, $A, $B, $C, $words[4], 11, 0x4bdecfa9);
+        self::step($H, $C, $D, $A, $B, $words[7], 16, 0xf6bb4b60);
+        self::step($H, $B, $C, $D, $A, $words[10], 23, 0xbebfbc70);
+        self::step($H, $A, $B, $C, $D, $words[13], 4, 0x289b7ec6);
+        self::step($H, $D, $A, $B, $C, $words[0], 11, 0xeaa127fa);
+        self::step($H, $C, $D, $A, $B, $words[3], 16, 0xd4ef3085);
+        self::step($H, $B, $C, $D, $A, $words[6], 23, 0x04881d05);
+        self::step($H, $A, $B, $C, $D, $words[9], 4, 0xd9d4d039);
+        self::step($H, $D, $A, $B, $C, $words[12], 11, 0xe6db99e5);
+        self::step($H, $C, $D, $A, $B, $words[15], 16, 0x1fa27cf8);
+        self::step($H, $B, $C, $D, $A, $words[2], 23, 0xc4ac5665);
+
+        /* ROUND 4 */
+        self::step($I, $A, $B, $C, $D, $words[0], 6, 0xf4292244);
+        self::step($I, $D, $A, $B, $C, $words[7], 10, 0x432aff97);
+        self::step($I, $C, $D, $A, $B, $words[14], 15, 0xab9423a7);
+        self::step($I, $B, $C, $D, $A, $words[5], 21, 0xfc93a039);
+        self::step($I, $A, $B, $C, $D, $words[12], 6, 0x655b59c3);
+        self::step($I, $D, $A, $B, $C, $words[3], 10, 0x8f0ccc92);
+        self::step($I, $C, $D, $A, $B, $words[10], 15, 0xffeff47d);
+        self::step($I, $B, $C, $D, $A, $words[1], 21, 0x85845dd1);
+        self::step($I, $A, $B, $C, $D, $words[8], 6, 0x6fa87e4f);
+        self::step($I, $D, $A, $B, $C, $words[15], 10, 0xfe2ce6e0);
+        self::step($I, $C, $D, $A, $B, $words[6], 15, 0xa3014314);
+        self::step($I, $B, $C, $D, $A, $words[13], 21, 0x4e0811a1);
+        self::step($I, $A, $B, $C, $D, $words[4], 6, 0xf7537e82);
+        self::step($I, $D, $A, $B, $C, $words[11], 10, 0xbd3af235);
+        self::step($I, $C, $D, $A, $B, $words[2], 15, 0x2ad7d2bb);
+        self::step($I, $B, $C, $D, $A, $words[9], 21, 0xeb86d391);
+
+        $this->a = ($this->a + $A) & 0xffffffff;
+        $this->b = ($this->b + $B) & 0xffffffff;
+        $this->c = ($this->c + $C) & 0xffffffff;
+        $this->d = ($this->d + $D) & 0xffffffff;
+    }
+
+    private static function f($X, $Y, $Z)
+    {
+        return (($X & $Y) | ((~ $X) & $Z)); // X AND Y OR NOT X AND Z
+    }
+
+    private static function g($X, $Y, $Z)
+    {
+        return (($X & $Z) | ($Y & (~ $Z))); // X AND Z OR Y AND NOT Z
+    }
+
+    private static function h($X, $Y, $Z)
+    {
+        return ($X ^ $Y ^ $Z); // X XOR Y XOR Z
+    }
+
+    private static function i($X, $Y, $Z)
+    {
+        return ($Y ^ ($X | (~ $Z))) ; // Y XOR (X OR NOT Z)
+    }
+
+    private static function step($func, &$A, $B, $C, $D, $M, $s, $t)
+    {
+        $A = ($A + call_user_func($func, $B, $C, $D) + $M + $t) & 0xffffffff;
+        $A = self::rotate($A, $s);
+        $A = ($B + $A) & 0xffffffff;
+    }
+
+    private static function rotate($decimal, $bits)
+    {
+        $binary = str_pad(decbin($decimal), 32, "0", STR_PAD_LEFT);
+        return bindec(substr($binary, $bits).substr($binary, 0, $bits));
+    }
+}

+ 81 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/RC4.php

@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * PHPExcel_Reader_Excel5_RC4
+ *
+ * Copyright (c) 2006 - 2015 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_Reader_Excel5
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_Excel5_RC4
+{
+    // Context
+    protected $s = array();
+    protected $i = 0;
+    protected $j = 0;
+
+    /**
+     * RC4 stream decryption/encryption constrcutor
+     *
+     * @param string $key Encryption key/passphrase
+     */
+    public function __construct($key)
+    {
+        $len = strlen($key);
+
+        for ($this->i = 0; $this->i < 256; $this->i++) {
+            $this->s[$this->i] = $this->i;
+        }
+
+        $this->j = 0;
+        for ($this->i = 0; $this->i < 256; $this->i++) {
+            $this->j = ($this->j + $this->s[$this->i] + ord($key[$this->i % $len])) % 256;
+            $t = $this->s[$this->i];
+            $this->s[$this->i] = $this->s[$this->j];
+            $this->s[$this->j] = $t;
+        }
+        $this->i = $this->j = 0;
+    }
+
+    /**
+     * Symmetric decryption/encryption function
+     *
+     * @param string $data Data to encrypt/decrypt
+     *
+     * @return string
+     */
+    public function RC4($data)
+    {
+        $len = strlen($data);
+        for ($c = 0; $c < $len; $c++) {
+            $this->i = ($this->i + 1) % 256;
+            $this->j = ($this->j + $this->s[$this->i]) % 256;
+            $t = $this->s[$this->i];
+            $this->s[$this->i] = $this->s[$this->j];
+            $this->s[$this->j] = $t;
+
+            $t = ($this->s[$this->i] + $this->s[$this->j]) % 256;
+
+            $data[$c] = chr(ord($data[$c]) ^ $this->s[$t]);
+        }
+        return $data;
+    }
+}

+ 36 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Style/Border.php

@@ -0,0 +1,36 @@
+<?php
+
+class PHPExcel_Reader_Excel5_Style_Border
+{
+    protected static $map = array(
+        0x00 => PHPExcel_Style_Border::BORDER_NONE,
+        0x01 => PHPExcel_Style_Border::BORDER_THIN,
+        0x02 => PHPExcel_Style_Border::BORDER_MEDIUM,
+        0x03 => PHPExcel_Style_Border::BORDER_DASHED,
+        0x04 => PHPExcel_Style_Border::BORDER_DOTTED,
+        0x05 => PHPExcel_Style_Border::BORDER_THICK,
+        0x06 => PHPExcel_Style_Border::BORDER_DOUBLE,
+        0x07 => PHPExcel_Style_Border::BORDER_HAIR,
+        0x08 => PHPExcel_Style_Border::BORDER_MEDIUMDASHED,
+        0x09 => PHPExcel_Style_Border::BORDER_DASHDOT,
+        0x0A => PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT,
+        0x0B => PHPExcel_Style_Border::BORDER_DASHDOTDOT,
+        0x0C => PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT,
+        0x0D => PHPExcel_Style_Border::BORDER_SLANTDASHDOT,
+    );
+
+    /**
+     * Map border style
+     * OpenOffice documentation: 2.5.11
+     *
+     * @param int $index
+     * @return string
+     */
+    public static function lookup($index)
+    {
+        if (isset(self::$map[$index])) {
+            return self::$map[$index];
+        }
+        return PHPExcel_Style_Border::BORDER_NONE;
+    }
+}

+ 41 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Excel5/Style/FillPattern.php

@@ -0,0 +1,41 @@
+<?php
+
+class PHPExcel_Reader_Excel5_Style_FillPattern
+{
+    protected static $map = array(
+        0x00 => PHPExcel_Style_Fill::FILL_NONE,
+        0x01 => PHPExcel_Style_Fill::FILL_SOLID,
+        0x02 => PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY,
+        0x03 => PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY,
+        0x04 => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY,
+        0x05 => PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL,
+        0x06 => PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL,
+        0x07 => PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN,
+        0x08 => PHPExcel_Style_Fill::FILL_PATTERN_DARKUP,
+        0x09 => PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID,
+        0x0A => PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS,
+        0x0B => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL,
+        0x0C => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL,
+        0x0D => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN,
+        0x0E => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP,
+        0x0F => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID,
+        0x10 => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS,
+        0x11 => PHPExcel_Style_Fill::FILL_PATTERN_GRAY125,
+        0x12 => PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625,
+    );
+
+    /**
+     * Get fill pattern from index
+     * OpenOffice documentation: 2.5.12
+     *
+     * @param int $index
+     * @return string
+     */
+    public static function lookup($index)
+    {
+        if (isset(self::$map[$index])) {
+            return self::$map[$index];
+        }
+        return PHPExcel_Style_Fill::FILL_NONE;
+    }
+}

+ 46 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Exception.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * PHPExcel_Reader_Exception
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_Exception extends PHPExcel_Exception
+{
+    /**
+     * Error handler callback
+     *
+     * @param mixed $code
+     * @param mixed $string
+     * @param mixed $file
+     * @param mixed $line
+     * @param mixed $context
+     */
+    public static function errorHandlerCallback($code, $string, $file, $line, $context)
+    {
+        $e = new self($string, $code);
+        $e->line = $line;
+        $e->file = $file;
+        throw $e;
+    }
+}

+ 850 - 0
backend/RTP/extend/excel/PHPExcel/Reader/Gnumeric.php

@@ -0,0 +1,850 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_Gnumeric
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_Gnumeric extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
+{
+    /**
+     * Formats
+     *
+     * @var array
+     */
+    private $styles = array();
+
+    /**
+     * Shared Expressions
+     *
+     * @var array
+     */
+    private $expressions = array();
+
+    private $referenceHelper = null;
+
+    /**
+     * 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
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function canRead($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        // Check if gzlib functions are available
+        if (!function_exists('gzread')) {
+            throw new PHPExcel_Reader_Exception("gzlib library is not enabled");
+        }
+
+        // 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;
+    }
+
+    /**
+     * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+     *
+     * @param     string         $pFilename
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function listWorksheetNames($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        $xml = new XMLReader();
+        $xml->xml($this->securityScanFile('compress.zlib://'.realpath($pFilename)), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+        $xml->setParserProperty(2, true);
+
+        $worksheetNames = array();
+        while ($xml->read()) {
+            if ($xml->name == 'gnm:SheetName' && $xml->nodeType == XMLReader::ELEMENT) {
+                $xml->read();    //    Move onto the value node
+                $worksheetNames[] = (string) $xml->value;
+            } elseif ($xml->name == 'gnm:Sheets') {
+                //    break out of the loop once we've got our sheet names rather than parse the entire file
+                break;
+            }
+        }
+
+        return $worksheetNames;
+    }
+
+    /**
+     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+     *
+     * @param   string     $pFilename
+     * @throws   PHPExcel_Reader_Exception
+     */
+    public function listWorksheetInfo($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        $xml = new XMLReader();
+        $xml->xml($this->securityScanFile('compress.zlib://'.realpath($pFilename)), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+        $xml->setParserProperty(2, true);
+
+        $worksheetInfo = array();
+        while ($xml->read()) {
+            if ($xml->name == 'gnm:Sheet' && $xml->nodeType == XMLReader::ELEMENT) {
+                $tmpInfo = array(
+                    'worksheetName' => '',
+                    'lastColumnLetter' => 'A',
+                    'lastColumnIndex' => 0,
+                    'totalRows' => 0,
+                    'totalColumns' => 0,
+                );
+
+                while ($xml->read()) {
+                    if ($xml->name == 'gnm:Name' && $xml->nodeType == XMLReader::ELEMENT) {
+                        $xml->read();    //    Move onto the value node
+                        $tmpInfo['worksheetName'] = (string) $xml->value;
+                    } elseif ($xml->name == 'gnm:MaxCol' && $xml->nodeType == XMLReader::ELEMENT) {
+                        $xml->read();    //    Move onto the value node
+                        $tmpInfo['lastColumnIndex'] = (int) $xml->value;
+                        $tmpInfo['totalColumns'] = (int) $xml->value + 1;
+                    } elseif ($xml->name == 'gnm:MaxRow' && $xml->nodeType == XMLReader::ELEMENT) {
+                        $xml->read();    //    Move onto the value node
+                        $tmpInfo['totalRows'] = (int) $xml->value + 1;
+                        break;
+                    }
+                }
+                $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+                $worksheetInfo[] = $tmpInfo;
+            }
+        }
+
+        return $worksheetInfo;
+    }
+
+    private function gzfileGetContents($filename)
+    {
+        $file = @gzopen($filename, 'rb');
+        if ($file !== false) {
+            $data = '';
+            while (!gzeof($file)) {
+                $data .= gzread($file, 1024);
+            }
+            gzclose($file);
+        }
+        return $data;
+    }
+
+    /**
+     * Loads PHPExcel from file
+     *
+     * @param     string         $pFilename
+     * @return     PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function load($pFilename)
+    {
+        // Create new PHPExcel
+        $objPHPExcel = new PHPExcel();
+
+        // Load into this instance
+        return $this->loadIntoExisting($pFilename, $objPHPExcel);
+    }
+
+    /**
+     * Loads PHPExcel from file into PHPExcel instance
+     *
+     * @param     string         $pFilename
+     * @param    PHPExcel    $objPHPExcel
+     * @return     PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_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 '<pre>';
+//        echo htmlentities($gFileData,ENT_QUOTES,'UTF-8');
+//        echo '</pre><hr />';
+//
+        $xml = simplexml_load_string($this->securityScan($gFileData), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+        $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 '<b>Worksheet: ', $worksheetName,'</b><br />';
+            if ((isset($this->loadSheetsOnly)) && (!in_array($worksheetName, $this->loadSheetsOnly))) {
+                continue;
+            }
+
+            $maxRow = $maxCol = 0;
+
+            // Create new Worksheet
+            $objPHPExcel->createSheet();
+            $objPHPExcel->setActiveSheetIndex($worksheetID);
+            //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
+            //        cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
+            //        name in line with the formula, not the reverse
+            $objPHPExcel->getActiveSheet()->setTitle($worksheetName, false);
+
+            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 ($this->getReadFilter() !== null) {
+                    if (!$this->getReadFilter()->readCell($column, $row, $worksheetName)) {
+                        continue;
+                    }
+                }
+
+                $ValueType = $cellAttributes->ValueType;
+                $ExprID = (string) $cellAttributes->ExprID;
+//                echo 'Cell ', $column, $row,'<br />';
+//                echo 'Type is ', $ValueType,'<br />';
+//                echo 'Value is ', $cell,'<br />';
+                $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,'<br />';
+                    } 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,'<br />';
+//                        echo 'New Value is ', $cell,'<br />';
+                    }
+                    $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);
+                            // Excel 2007+ doesn't differentiate between integer and float, so set the value and dropthru to the next (numeric) case
+                        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,'<br />';
+//
+            foreach ($sheet->Styles->StyleRegion as $styleRegion) {
+                $styleAttributes = $styleRegion->attributes();
+                if (($styleAttributes['startRow'] <= $maxRow) &&
+                    ($styleAttributes['startCol'] <= $maxCol)) {
+                    $startColumn = PHPExcel_Cell::stringFromColumnIndex((int) $styleAttributes['startCol']);
+                    $startRow = $styleAttributes['startRow'] + 1;
+
+                    $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol'];
+                    $endColumn = PHPExcel_Cell::stringFromColumnIndex($endColumn);
+                    $endRow = ($styleAttributes['endRow'] > $maxRow) ? $maxRow : $styleAttributes['endRow'];
+                    $endRow += 1;
+                    $cellRange = $startColumn.$startRow.':'.$endColumn.$endRow;
+//                    echo $cellRange,'<br />';
+
+                    $styleAttributes = $styleRegion->Style->attributes();
+//                    var_dump($styleAttributes);
+//                    echo '<br />';
+
+                    //    We still set the number format mask for date/time values, even if readDataOnly is true
+                    if ((!$this->readDataOnly) ||
+                        (PHPExcel_Shared_Date::isDateTimeFormatCode((string) $styleAttributes['Format']))) {
+                        $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 '<br />';
+                            $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 '<br />';
+                        $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) {
+                    if (strpos($mergeCells, ':') !== false) {
+                        $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"])) {
+            $styleArray['color']['rgb'] = self::parseGnumericColour($borderAttributes["Color"]);
+        }
+
+        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 '3':
+                $styleArray['style'] = PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
+                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 '8':
+                $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
+                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;
+        }
+        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);
+        return $gnmR . $gnmG . $gnmB;
+    }
+}

+ 549 - 0
backend/RTP/extend/excel/PHPExcel/Reader/HTML.php

@@ -0,0 +1,549 @@
+<?php
+
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_HTML
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+/** PHPExcel root directory */
+class PHPExcel_Reader_HTML extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
+{
+
+    /**
+     * Input encoding
+     *
+     * @var string
+     */
+    protected $inputEncoding = 'ANSI';
+
+    /**
+     * Sheet index to read
+     *
+     * @var int
+     */
+    protected $sheetIndex = 0;
+
+    /**
+     * Formats
+     *
+     * @var array
+     */
+    protected $formats = array(
+        'h1' => array(
+            'font' => array(
+                'bold' => true,
+                'size' => 24,
+            ),
+        ), //    Bold, 24pt
+        'h2' => array(
+            'font' => array(
+                'bold' => true,
+                'size' => 18,
+            ),
+        ), //    Bold, 18pt
+        'h3' => array(
+            'font' => array(
+                'bold' => true,
+                'size' => 13.5,
+            ),
+        ), //    Bold, 13.5pt
+        'h4' => array(
+            'font' => array(
+                'bold' => true,
+                'size' => 12,
+            ),
+        ), //    Bold, 12pt
+        'h5' => array(
+            'font' => array(
+                'bold' => true,
+                'size' => 10,
+            ),
+        ), //    Bold, 10pt
+        'h6' => array(
+            'font' => array(
+                'bold' => true,
+                'size' => 7.5,
+            ),
+        ), //    Bold, 7.5pt
+        'a' => array(
+            'font' => array(
+                'underline' => true,
+                'color' => array(
+                    'argb' => PHPExcel_Style_Color::COLOR_BLUE,
+                ),
+            ),
+        ), //    Blue underlined
+        'hr' => array(
+            'borders' => array(
+                'bottom' => array(
+                    'style' => PHPExcel_Style_Border::BORDER_THIN,
+                    'color' => array(
+                        PHPExcel_Style_Color::COLOR_BLACK,
+                    ),
+                ),
+            ),
+        ), //    Bottom border
+    );
+
+    protected $rowspan = array();
+
+    /**
+     * Create a new PHPExcel_Reader_HTML
+     */
+    public function __construct()
+    {
+        $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
+    }
+
+    /**
+     * Validate that the current file is an HTML file
+     *
+     * @return boolean
+     */
+    protected function isValidFormat()
+    {
+        //    Reading 2048 bytes should be enough to validate that the format is HTML
+        $data = fread($this->fileHandle, 2048);
+        if ((strpos($data, '<') !== false) &&
+                (strlen($data) !== strlen(strip_tags($data)))) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Loads PHPExcel from file
+     *
+     * @param  string                    $pFilename
+     * @return PHPExcel
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function load($pFilename)
+    {
+        // Create new PHPExcel
+        $objPHPExcel = new PHPExcel();
+
+        // Load into this instance
+        return $this->loadIntoExisting($pFilename, $objPHPExcel);
+    }
+
+    /**
+     * Set input encoding
+     *
+     * @param string $pValue Input encoding
+     */
+    public function setInputEncoding($pValue = 'ANSI')
+    {
+        $this->inputEncoding = $pValue;
+
+        return $this;
+    }
+
+    /**
+     * Get input encoding
+     *
+     * @return string
+     */
+    public function getInputEncoding()
+    {
+        return $this->inputEncoding;
+    }
+
+    //    Data Array used for testing only, should write to PHPExcel object on completion of tests
+    protected $dataArray = array();
+    protected $tableLevel = 0;
+    protected $nestedColumn = array('A');
+
+    protected function setTableStartColumn($column)
+    {
+        if ($this->tableLevel == 0) {
+            $column = 'A';
+        }
+        ++$this->tableLevel;
+        $this->nestedColumn[$this->tableLevel] = $column;
+
+        return $this->nestedColumn[$this->tableLevel];
+    }
+
+    protected function getTableStartColumn()
+    {
+        return $this->nestedColumn[$this->tableLevel];
+    }
+
+    protected function releaseTableStartColumn()
+    {
+        --$this->tableLevel;
+
+        return array_pop($this->nestedColumn);
+    }
+
+    protected function flushCell($sheet, $column, $row, &$cellContent)
+    {
+        if (is_string($cellContent)) {
+            //    Simple String content
+            if (trim($cellContent) > '') {
+                //    Only actually write it if there's content in the string
+//                echo 'FLUSH CELL: ' , $column , $row , ' => ' , $cellContent , '<br />';
+                //    Write to worksheet to be done here...
+                //    ... we return the cell so we can mess about with styles more easily
+                $sheet->setCellValue($column . $row, $cellContent, true);
+                $this->dataArray[$row][$column] = $cellContent;
+            }
+        } else {
+            //    We have a Rich Text run
+            //    TODO
+            $this->dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
+        }
+        $cellContent = (string) '';
+    }
+
+    protected function processDomElement(DOMNode $element, $sheet, &$row, &$column, &$cellContent, $format = null)
+    {
+        foreach ($element->childNodes as $child) {
+            if ($child instanceof DOMText) {
+                $domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
+                if (is_string($cellContent)) {
+                    //    simply append the text if the cell content is a plain text string
+                    $cellContent .= $domText;
+                } else {
+                    //    but if we have a rich text run instead, we need to append it correctly
+                    //    TODO
+                }
+            } elseif ($child instanceof DOMElement) {
+//                echo '<b>DOM ELEMENT: </b>' , strtoupper($child->nodeName) , '<br />';
+
+                $attributeArray = array();
+                foreach ($child->attributes as $attribute) {
+//                    echo '<b>ATTRIBUTE: </b>' , $attribute->name , ' => ' , $attribute->value , '<br />';
+                    $attributeArray[$attribute->name] = $attribute->value;
+                }
+
+                switch ($child->nodeName) {
+                    case 'meta':
+                        foreach ($attributeArray as $attributeName => $attributeValue) {
+                            switch ($attributeName) {
+                                case 'content':
+                                    //    TODO
+                                    //    Extract character set, so we can convert to UTF-8 if required
+                                    break;
+                            }
+                        }
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+                        break;
+                    case 'title':
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+                        $sheet->setTitle($cellContent);
+                        $cellContent = '';
+                        break;
+                    case 'span':
+                    case 'div':
+                    case 'font':
+                    case 'i':
+                    case 'em':
+                    case 'strong':
+                    case 'b':
+//                        echo 'STYLING, SPAN OR DIV<br />';
+                        if ($cellContent > '') {
+                            $cellContent .= ' ';
+                        }
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+                        if ($cellContent > '') {
+                            $cellContent .= ' ';
+                        }
+//                        echo 'END OF STYLING, SPAN OR DIV<br />';
+                        break;
+                    case 'hr':
+                        $this->flushCell($sheet, $column, $row, $cellContent);
+                        ++$row;
+                        if (isset($this->formats[$child->nodeName])) {
+                            $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
+                        } else {
+                            $cellContent = '----------';
+                            $this->flushCell($sheet, $column, $row, $cellContent);
+                        }
+                        ++$row;
+                        // Add a break after a horizontal rule, simply by allowing the code to dropthru
+                    case 'br':
+                        if ($this->tableLevel > 0) {
+                            //    If we're inside a table, replace with a \n
+                            $cellContent .= "\n";
+                        } else {
+                            //    Otherwise flush our existing content and move the row cursor on
+                            $this->flushCell($sheet, $column, $row, $cellContent);
+                            ++$row;
+                        }
+//                        echo 'HARD LINE BREAK: ' , '<br />';
+                        break;
+                    case 'a':
+//                        echo 'START OF HYPERLINK: ' , '<br />';
+                        foreach ($attributeArray as $attributeName => $attributeValue) {
+                            switch ($attributeName) {
+                                case 'href':
+//                                    echo 'Link to ' , $attributeValue , '<br />';
+                                    $sheet->getCell($column . $row)->getHyperlink()->setUrl($attributeValue);
+                                    if (isset($this->formats[$child->nodeName])) {
+                                        $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
+                                    }
+                                    break;
+                            }
+                        }
+                        $cellContent .= ' ';
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+//                        echo 'END OF HYPERLINK:' , '<br />';
+                        break;
+                    case 'h1':
+                    case 'h2':
+                    case 'h3':
+                    case 'h4':
+                    case 'h5':
+                    case 'h6':
+                    case 'ol':
+                    case 'ul':
+                    case 'p':
+                        if ($this->tableLevel > 0) {
+                            //    If we're inside a table, replace with a \n
+                            $cellContent .= "\n";
+//                            echo 'LIST ENTRY: ' , '<br />';
+                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+//                            echo 'END OF LIST ENTRY:' , '<br />';
+                        } else {
+                            if ($cellContent > '') {
+                                $this->flushCell($sheet, $column, $row, $cellContent);
+                                $row++;
+                            }
+//                            echo 'START OF PARAGRAPH: ' , '<br />';
+                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+//                            echo 'END OF PARAGRAPH:' , '<br />';
+                            $this->flushCell($sheet, $column, $row, $cellContent);
+
+                            if (isset($this->formats[$child->nodeName])) {
+                                $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
+                            }
+
+                            $row++;
+                            $column = 'A';
+                        }
+                        break;
+                    case 'li':
+                        if ($this->tableLevel > 0) {
+                            //    If we're inside a table, replace with a \n
+                            $cellContent .= "\n";
+//                            echo 'LIST ENTRY: ' , '<br />';
+                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+//                            echo 'END OF LIST ENTRY:' , '<br />';
+                        } else {
+                            if ($cellContent > '') {
+                                $this->flushCell($sheet, $column, $row, $cellContent);
+                            }
+                            ++$row;
+//                            echo 'LIST ENTRY: ' , '<br />';
+                            $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+//                            echo 'END OF LIST ENTRY:' , '<br />';
+                            $this->flushCell($sheet, $column, $row, $cellContent);
+                            $column = 'A';
+                        }
+                        break;
+                    case 'table':
+                        $this->flushCell($sheet, $column, $row, $cellContent);
+                        $column = $this->setTableStartColumn($column);
+//                        echo 'START OF TABLE LEVEL ' , $this->tableLevel , '<br />';
+                        if ($this->tableLevel > 1) {
+                            --$row;
+                        }
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+//                        echo 'END OF TABLE LEVEL ' , $this->tableLevel , '<br />';
+                        $column = $this->releaseTableStartColumn();
+                        if ($this->tableLevel > 1) {
+                            ++$column;
+                        } else {
+                            ++$row;
+                        }
+                        break;
+                    case 'thead':
+                    case 'tbody':
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+                        break;
+                    case 'tr':
+                        $column = $this->getTableStartColumn();
+                        $cellContent = '';
+//                        echo 'START OF TABLE ' , $this->tableLevel , ' ROW<br />';
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+                        ++$row;
+//                        echo 'END OF TABLE ' , $this->tableLevel , ' ROW<br />';
+                        break;
+                    case 'th':
+                    case 'td':
+//                        echo 'START OF TABLE ' , $this->tableLevel , ' CELL<br />';
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+//                        echo 'END OF TABLE ' , $this->tableLevel , ' CELL<br />';
+
+                        while (isset($this->rowspan[$column . $row])) {
+                            ++$column;
+                        }
+
+                        $this->flushCell($sheet, $column, $row, $cellContent);
+
+//                        if (isset($attributeArray['style']) && !empty($attributeArray['style'])) {
+//                            $styleAry = $this->getPhpExcelStyleArray($attributeArray['style']);
+//
+//                            if (!empty($styleAry)) {
+//                                $sheet->getStyle($column . $row)->applyFromArray($styleAry);
+//                            }
+//                        }
+
+                        if (isset($attributeArray['rowspan']) && isset($attributeArray['colspan'])) {
+                            //create merging rowspan and colspan
+                            $columnTo = $column;
+                            for ($i = 0; $i < $attributeArray['colspan'] - 1; $i++) {
+                                ++$columnTo;
+                            }
+                            $range = $column . $row . ':' . $columnTo . ($row + $attributeArray['rowspan'] - 1);
+                            foreach (\PHPExcel_Cell::extractAllCellReferencesInRange($range) as $value) {
+                                $this->rowspan[$value] = true;
+                            }
+                            $sheet->mergeCells($range);
+                            $column = $columnTo;
+                        } elseif (isset($attributeArray['rowspan'])) {
+                            //create merging rowspan
+                            $range = $column . $row . ':' . $column . ($row + $attributeArray['rowspan'] - 1);
+                            foreach (\PHPExcel_Cell::extractAllCellReferencesInRange($range) as $value) {
+                                $this->rowspan[$value] = true;
+                            }
+                            $sheet->mergeCells($range);
+                        } elseif (isset($attributeArray['colspan'])) {
+                            //create merging colspan
+                            $columnTo = $column;
+                            for ($i = 0; $i < $attributeArray['colspan'] - 1; $i++) {
+                                ++$columnTo;
+                            }
+                            $sheet->mergeCells($column . $row . ':' . $columnTo . $row);
+                            $column = $columnTo;
+                        }
+                        ++$column;
+                        break;
+                    case 'body':
+                        $row = 1;
+                        $column = 'A';
+                        $content = '';
+                        $this->tableLevel = 0;
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+                        break;
+                    default:
+                        $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+                }
+            }
+        }
+    }
+
+    /**
+     * Loads PHPExcel from file into PHPExcel instance
+     *
+     * @param  string                    $pFilename
+     * @param  PHPExcel                  $objPHPExcel
+     * @return PHPExcel
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+    {
+        // Open file to validate
+        $this->openFile($pFilename);
+        if (!$this->isValidFormat()) {
+            fclose($this->fileHandle);
+            throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid HTML file.");
+        }
+        //    Close after validating
+        fclose($this->fileHandle);
+
+        // Create new PHPExcel
+        while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) {
+            $objPHPExcel->createSheet();
+        }
+        $objPHPExcel->setActiveSheetIndex($this->sheetIndex);
+
+        //    Create a new DOM object
+        $dom = new domDocument;
+        //    Reload the HTML file into the DOM object
+        $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
+        if ($loaded === false) {
+            throw new PHPExcel_Reader_Exception('Failed to load ' . $pFilename . ' as a DOM Document');
+        }
+
+        //    Discard white space
+        $dom->preserveWhiteSpace = false;
+
+        $row = 0;
+        $column = 'A';
+        $content = '';
+        $this->processDomElement($dom, $objPHPExcel->getActiveSheet(), $row, $column, $content);
+
+        // Return
+        return $objPHPExcel;
+    }
+
+    /**
+     * Get sheet index
+     *
+     * @return int
+     */
+    public function getSheetIndex()
+    {
+        return $this->sheetIndex;
+    }
+
+    /**
+     * Set sheet index
+     *
+     * @param  int                  $pValue Sheet index
+     * @return PHPExcel_Reader_HTML
+     */
+    public function setSheetIndex($pValue = 0)
+    {
+        $this->sheetIndex = $pValue;
+
+        return $this;
+    }
+
+    /**
+     * Scan theXML for use of <!ENTITY to prevent XXE/XEE attacks
+     *
+     * @param     string         $xml
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function securityScan($xml)
+    {
+        $pattern = '/\\0?' . implode('\\0?', str_split('<!ENTITY')) . '\\0?/';
+        if (preg_match($pattern, $xml)) {
+            throw new PHPExcel_Reader_Exception('Detected use of ENTITY in XML, spreadsheet file load() aborted to prevent XXE/XEE attacks');
+        }
+        return $xml;
+    }
+}

+ 39 - 0
backend/RTP/extend/excel/PHPExcel/Reader/IReadFilter.php

@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * PHPExcel_Reader_IReadFilter
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+interface PHPExcel_Reader_IReadFilter
+{
+    /**
+     * Should this cell be read?
+     *
+     * @param    $column           Column address (as a string value like "A", or "IV")
+     * @param    $row              Row number
+     * @param    $worksheetName    Optional worksheet name
+     * @return   boolean
+     */
+    public function readCell($column, $row, $worksheetName = '');
+}

+ 46 - 0
backend/RTP/extend/excel/PHPExcel/Reader/IReader.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * PHPExcel_Reader_IReader
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+interface PHPExcel_Reader_IReader
+{
+    /**
+     * Can the current PHPExcel_Reader_IReader read the file?
+     *
+     * @param     string         $pFilename
+     * @return     boolean
+     */
+    public function canRead($pFilename);
+
+    /**
+     * Loads PHPExcel from file
+     *
+     * @param     string         $pFilename
+     * @return  PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function load($pFilename);
+}

+ 696 - 0
backend/RTP/extend/excel/PHPExcel/Reader/OOCalc.php

@@ -0,0 +1,696 @@
+<?php
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+    /**
+     * @ignore
+     */
+    define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+    require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_OOCalc
+ *
+ * Copyright (c) 2006 - 2015 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_Reader
+ * @copyright  Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    ##VERSION##, ##DATE##
+ */
+class PHPExcel_Reader_OOCalc extends PHPExcel_Reader_Abstract implements PHPExcel_Reader_IReader
+{
+    /**
+     * Formats
+     *
+     * @var array
+     */
+    private $styles = array();
+
+    /**
+     * Create a new PHPExcel_Reader_OOCalc
+     */
+    public function __construct()
+    {
+        $this->readFilter     = new PHPExcel_Reader_DefaultReadFilter();
+    }
+
+    /**
+     * Can the current PHPExcel_Reader_IReader read the file?
+     *
+     * @param     string         $pFilename
+     * @return     boolean
+     * @throws PHPExcel_Reader_Exception
+     */
+    public function canRead($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        $zipClass = PHPExcel_Settings::getZipClass();
+
+        // Check if zip class exists
+//        if (!class_exists($zipClass, false)) {
+//            throw new PHPExcel_Reader_Exception($zipClass . " library is not enabled");
+//        }
+
+        $mimeType = 'UNKNOWN';
+        // Load file
+        $zip = new $zipClass;
+        if ($zip->open($pFilename) === true) {
+            // check if it is an OOXML archive
+            $stat = $zip->statName('mimetype');
+            if ($stat && ($stat['size'] <= 255)) {
+                $mimeType = $zip->getFromName($stat['name']);
+            } elseif ($stat = $zip->statName('META-INF/manifest.xml')) {
+                $xml = simplexml_load_string($this->securityScan($zip->getFromName('META-INF/manifest.xml')), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+                $namespacesContent = $xml->getNamespaces(true);
+                if (isset($namespacesContent['manifest'])) {
+                    $manifest = $xml->children($namespacesContent['manifest']);
+                    foreach ($manifest as $manifestDataSet) {
+                        $manifestAttributes = $manifestDataSet->attributes($namespacesContent['manifest']);
+                        if ($manifestAttributes->{'full-path'} == '/') {
+                            $mimeType = (string) $manifestAttributes->{'media-type'};
+                            break;
+                        }
+                    }
+                }
+            }
+
+            $zip->close();
+
+            return ($mimeType === 'application/vnd.oasis.opendocument.spreadsheet');
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+     *
+     * @param     string         $pFilename
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function listWorksheetNames($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        $zipClass = PHPExcel_Settings::getZipClass();
+
+        $zip = new $zipClass;
+        if (!$zip->open($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! Error opening file.");
+        }
+
+        $worksheetNames = array();
+
+        $xml = new XMLReader();
+        $res = $xml->xml($this->securityScanFile('zip://'.realpath($pFilename).'#content.xml'), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+        $xml->setParserProperty(2, true);
+
+        //    Step into the first level of content of the XML
+        $xml->read();
+        while ($xml->read()) {
+            //    Quickly jump through to the office:body node
+            while ($xml->name !== 'office:body') {
+                if ($xml->isEmptyElement) {
+                    $xml->read();
+                } else {
+                    $xml->next();
+                }
+            }
+            //    Now read each node until we find our first table:table node
+            while ($xml->read()) {
+                if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
+                    //    Loop through each table:table node reading the table:name attribute for each worksheet name
+                    do {
+                        $worksheetNames[] = $xml->getAttribute('table:name');
+                        $xml->next();
+                    } while ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT);
+                }
+            }
+        }
+
+        return $worksheetNames;
+    }
+
+    /**
+     * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+     *
+     * @param   string     $pFilename
+     * @throws   PHPExcel_Reader_Exception
+     */
+    public function listWorksheetInfo($pFilename)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        $worksheetInfo = array();
+
+        $zipClass = PHPExcel_Settings::getZipClass();
+
+        $zip = new $zipClass;
+        if (!$zip->open($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! Error opening file.");
+        }
+
+        $xml = new XMLReader();
+        $res = $xml->xml($this->securityScanFile('zip://'.realpath($pFilename).'#content.xml'), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+        $xml->setParserProperty(2, true);
+
+        //    Step into the first level of content of the XML
+        $xml->read();
+        while ($xml->read()) {
+            //    Quickly jump through to the office:body node
+            while ($xml->name !== 'office:body') {
+                if ($xml->isEmptyElement) {
+                    $xml->read();
+                } else {
+                    $xml->next();
+                }
+            }
+                //    Now read each node until we find our first table:table node
+            while ($xml->read()) {
+                if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
+                    $worksheetNames[] = $xml->getAttribute('table:name');
+
+                    $tmpInfo = array(
+                        'worksheetName' => $xml->getAttribute('table:name'),
+                        'lastColumnLetter' => 'A',
+                        'lastColumnIndex' => 0,
+                        'totalRows' => 0,
+                        'totalColumns' => 0,
+                    );
+
+                    //    Loop through each child node of the table:table element reading
+                    $currCells = 0;
+                    do {
+                        $xml->read();
+                        if ($xml->name == 'table:table-row' && $xml->nodeType == XMLReader::ELEMENT) {
+                            $rowspan = $xml->getAttribute('table:number-rows-repeated');
+                            $rowspan = empty($rowspan) ? 1 : $rowspan;
+                            $tmpInfo['totalRows'] += $rowspan;
+                            $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
+                            $currCells = 0;
+                            //    Step into the row
+                            $xml->read();
+                            do {
+                                if ($xml->name == 'table:table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
+                                    if (!$xml->isEmptyElement) {
+                                        $currCells++;
+                                        $xml->next();
+                                    } else {
+                                        $xml->read();
+                                    }
+                                } elseif ($xml->name == 'table:covered-table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
+                                    $mergeSize = $xml->getAttribute('table:number-columns-repeated');
+                                    $currCells += $mergeSize;
+                                    $xml->read();
+                                }
+                            } while ($xml->name != 'table:table-row');
+                        }
+                    } while ($xml->name != 'table:table');
+
+                    $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
+                    $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
+                    $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+                    $worksheetInfo[] = $tmpInfo;
+                }
+            }
+
+//                foreach ($workbookData->table as $worksheetDataSet) {
+//                    $worksheetData = $worksheetDataSet->children($namespacesContent['table']);
+//                    $worksheetDataAttributes = $worksheetDataSet->attributes($namespacesContent['table']);
+//
+//                    $rowIndex = 0;
+//                    foreach ($worksheetData as $key => $rowData) {
+//                        switch ($key) {
+//                            case 'table-row' :
+//                                $rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
+//                                $rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ?
+//                                        $rowDataTableAttributes['number-rows-repeated'] : 1;
+//                                $columnIndex = 0;
+//
+//                                foreach ($rowData as $key => $cellData) {
+//                                    $cellDataTableAttributes = $cellData->attributes($namespacesContent['table']);
+//                                    $colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ?
+//                                        $cellDataTableAttributes['number-columns-repeated'] : 1;
+//                                    $cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']);
+//                                    if (isset($cellDataOfficeAttributes['value-type'])) {
+//                                        $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex + $colRepeats - 1);
+//                                        $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex + $rowRepeats);
+//                                    }
+//                                    $columnIndex += $colRepeats;
+//                                }
+//                                $rowIndex += $rowRepeats;
+//                                break;
+//                        }
+//                    }
+//
+//                    $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+//                    $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+//
+//                }
+//            }
+        }
+
+        return $worksheetInfo;
+    }
+
+    /**
+     * Loads PHPExcel from file
+     *
+     * @param     string         $pFilename
+     * @return     PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function load($pFilename)
+    {
+        // Create new PHPExcel
+        $objPHPExcel = new PHPExcel();
+
+        // Load into this instance
+        return $this->loadIntoExisting($pFilename, $objPHPExcel);
+    }
+
+    private static function identifyFixedStyleValue($styleList, &$styleAttributeValue)
+    {
+        $styleAttributeValue = strtolower($styleAttributeValue);
+        foreach ($styleList as $style) {
+            if ($styleAttributeValue == strtolower($style)) {
+                $styleAttributeValue = $style;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Loads PHPExcel from file into PHPExcel instance
+     *
+     * @param     string         $pFilename
+     * @param    PHPExcel    $objPHPExcel
+     * @return     PHPExcel
+     * @throws     PHPExcel_Reader_Exception
+     */
+    public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+    {
+        // Check if file exists
+        if (!file_exists($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+        }
+
+        $timezoneObj = new DateTimeZone('Europe/London');
+        $GMT = new DateTimeZone('UTC');
+
+        $zipClass = PHPExcel_Settings::getZipClass();
+
+        $zip = new $zipClass;
+        if (!$zip->open($pFilename)) {
+            throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! Error opening file.");
+        }
+
+//        echo '<h1>Meta Information</h1>';
+        $xml = simplexml_load_string($this->securityScan($zip->getFromName("meta.xml")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+        $namespacesMeta = $xml->getNamespaces(true);
+//        echo '<pre>';
+//        print_r($namespacesMeta);
+//        echo '</pre><hr />';
+
+        $docProps = $objPHPExcel->getProperties();
+        $officeProperty = $xml->children($namespacesMeta['office']);
+        foreach ($officeProperty 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($propertyValue);
+                        break;
+                    case 'subject':
+                        $docProps->setSubject($propertyValue);
+                        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);
+                        break;
+                }
+            }
+            $officePropertyMeta = array();
+            if (isset($namespacesMeta['dc'])) {
+                $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
+            }
+            foreach ($officePropertyMeta as $propertyName => $propertyValue) {
+                $propertyValueAttributes = $propertyValue->attributes($namespacesMeta['meta']);
+                $propertyValue = (string) $propertyValue;
+                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;
+                }
+            }
+        }
+
+
+//        echo '<h1>Workbook Content</h1>';
+        $xml = simplexml_load_string($this->securityScan($zip->getFromName("content.xml")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+        $namespacesContent = $xml->getNamespaces(true);
+//        echo '<pre>';
+//        print_r($namespacesContent);
+//        echo '</pre><hr />';
+
+        $workbook = $xml->children($namespacesContent['office']);
+        foreach ($workbook->body->spreadsheet as $workbookData) {
+            $workbookData = $workbookData->children($namespacesContent['table']);
+            $worksheetID = 0;
+            foreach ($workbookData->table as $worksheetDataSet) {
+                $worksheetData = $worksheetDataSet->children($namespacesContent['table']);
+//                print_r($worksheetData);
+//                echo '<br />';
+                $worksheetDataAttributes = $worksheetDataSet->attributes($namespacesContent['table']);
+//                print_r($worksheetDataAttributes);
+//                echo '<br />';
+                if ((isset($this->loadSheetsOnly)) && (isset($worksheetDataAttributes['name'])) &&
+                    (!in_array($worksheetDataAttributes['name'], $this->loadSheetsOnly))) {
+                    continue;
+                }
+
+//                echo '<h2>Worksheet '.$worksheetDataAttributes['name'].'</h2>';
+                // Create new Worksheet
+                $objPHPExcel->createSheet();
+                $objPHPExcel->setActiveSheetIndex($worksheetID);
+                if (isset($worksheetDataAttributes['name'])) {
+                    $worksheetName = (string) $worksheetDataAttributes['name'];
+                    //    Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
+                    //        formula cells... during the load, all formulae should be correct, and we're simply
+                    //        bringing the worksheet name in line with the formula, not the reverse
+                    $objPHPExcel->getActiveSheet()->setTitle($worksheetName, false);
+                }
+
+                $rowID = 1;
+                foreach ($worksheetData as $key => $rowData) {
+//                    echo '<b>'.$key.'</b><br />';
+                    switch ($key) {
+                        case 'table-header-rows':
+                            foreach ($rowData as $key => $cellData) {
+                                $rowData = $cellData;
+                                break;
+                            }
+                        case 'table-row':
+                            $rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
+                            $rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ? $rowDataTableAttributes['number-rows-repeated'] : 1;
+                            $columnID = 'A';
+                            foreach ($rowData as $key => $cellData) {
+                                if ($this->getReadFilter() !== null) {
+                                    if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
+                                        continue;
+                                    }
+                                }
+
+//                                echo '<b>'.$columnID.$rowID.'</b><br />';
+                                $cellDataText = (isset($namespacesContent['text'])) ? $cellData->children($namespacesContent['text']) : '';
+                                $cellDataOffice = $cellData->children($namespacesContent['office']);
+                                $cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']);
+                                $cellDataTableAttributes = $cellData->attributes($namespacesContent['table']);
+
+//                                echo 'Office Attributes: ';
+//                                print_r($cellDataOfficeAttributes);
+//                                echo '<br />Table Attributes: ';
+//                                print_r($cellDataTableAttributes);
+//                                echo '<br />Cell Data Text';
+//                                print_r($cellDataText);
+//                                echo '<br />';
+//
+                                $type = $formatting = $hyperlink = null;
+                                $hasCalculatedValue = false;
+                                $cellDataFormula = '';
+                                if (isset($cellDataTableAttributes['formula'])) {
+                                    $cellDataFormula = $cellDataTableAttributes['formula'];
+                                    $hasCalculatedValue = true;
+                                }
+
+                                if (isset($cellDataOffice->annotation)) {
+//                                    echo 'Cell has comment<br />';
+                                    $annotationText = $cellDataOffice->annotation->children($namespacesContent['text']);
+                                    $textArray = array();
+                                    foreach ($annotationText as $t) {
+                                        if (isset($t->span)) {
+                                            foreach ($t->span as $text) {
+                                                $textArray[] = (string)$text;
+                                            }
+                                        } else {
+                                            $textArray[] = (string) $t;
+                                        }
+                                    }
+                                    $text = implode("\n", $textArray);
+//                                    echo $text, '<br />';
+                                    $objPHPExcel->getActiveSheet()->getComment($columnID.$rowID)->setText($this->parseRichText($text));
+//                                                                    ->setAuthor( $author )
+                                }
+
+                                if (isset($cellDataText->p)) {
+                                    // Consolidate if there are multiple p records (maybe with spans as well)
+                                    $dataArray = array();
+                                    // Text can have multiple text:p and within those, multiple text:span.
+                                    // text:p newlines, but text:span does not.
+                                    // Also, here we assume there is no text data is span fields are specified, since
+                                    // we have no way of knowing proper positioning anyway.
+                                    foreach ($cellDataText->p as $pData) {
+                                        if (isset($pData->span)) {
+                                            // span sections do not newline, so we just create one large string here
+                                            $spanSection = "";
+                                            foreach ($pData->span as $spanData) {
+                                                $spanSection .= $spanData;
+                                            }
+                                            array_push($dataArray, $spanSection);
+                                        } else {
+                                            array_push($dataArray, $pData);
+                                        }
+                                    }
+                                    $allCellDataText = implode($dataArray, "\n");
+
+//                                    echo 'Value Type is '.$cellDataOfficeAttributes['value-type'].'<br />';
+                                    switch ($cellDataOfficeAttributes['value-type']) {
+                                        case 'string':
+                                            $type = PHPExcel_Cell_DataType::TYPE_STRING;
+                                            $dataValue = $allCellDataText;
+                                            if (isset($dataValue->a)) {
+                                                $dataValue = $dataValue->a;
+                                                $cellXLinkAttributes = $dataValue->attributes($namespacesContent['xlink']);
+                                                $hyperlink = $cellXLinkAttributes['href'];
+                                            }
+                                            break;
+                                        case 'boolean':
+                                            $type = PHPExcel_Cell_DataType::TYPE_BOOL;
+                                            $dataValue = ($allCellDataText == 'TRUE') ? true : false;
+                                            break;
+                                        case 'percentage':
+                                            $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+                                            $dataValue = (float) $cellDataOfficeAttributes['value'];
+                                            if (floor($dataValue) == $dataValue) {
+                                                $dataValue = (integer) $dataValue;
+                                            }
+                                            $formatting = PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00;
+                                            break;
+                                        case 'currency':
+                                            $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+                                            $dataValue = (float) $cellDataOfficeAttributes['value'];
+                                            if (floor($dataValue) == $dataValue) {
+                                                $dataValue = (integer) $dataValue;
+                                            }
+                                            $formatting = PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE;
+                                            break;
+                                        case 'float':
+                                            $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+                                            $dataValue = (float) $cellDataOfficeAttributes['value'];
+                                            if (floor($dataValue) == $dataValue) {
+                                                if ($dataValue == (integer) $dataValue) {
+                                                    $dataValue = (integer) $dataValue;
+                                                } else {
+                                                    $dataValue = (float) $dataValue;
+                                                }
+                                            }
+                                            break;
+                                        case 'date':
+                                            $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+                                            $dateObj = new DateTime($cellDataOfficeAttributes['date-value'], $GMT);
+                                            $dateObj->setTimeZone($timezoneObj);
+                                            list($year, $month, $day, $hour, $minute, $second) = explode(' ', $dateObj->format('Y m d H i s'));
+                                            $dataValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day, $hour, $minute, $second);
+                                            if ($dataValue != floor($dataValue)) {
+                                                $formatting = PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15.' '.PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4;
+                                            } else {
+                                                $formatting = PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15;
+                                            }
+                                            break;
+                                        case 'time':
+                                            $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+                                            $dataValue = PHPExcel_Shared_Date::PHPToExcel(strtotime('01-01-1970 '.implode(':', sscanf($cellDataOfficeAttributes['time-value'], 'PT%dH%dM%dS'))));
+                                            $formatting = PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4;
+                                            break;
+                                    }
+//                                    echo 'Data value is '.$dataValue.'<br />';
+//                                    if ($hyperlink !== null) {
+//                                        echo 'Hyperlink is '.$hyperlink.'<br />';
+//                                    }
+                                } else {
+                                    $type = PHPExcel_Cell_DataType::TYPE_NULL;
+                                    $dataValue = null;
+                                }
+
+                                if ($hasCalculatedValue) {
+                                    $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
+//                                    echo 'Formula: ', $cellDataFormula, PHP_EOL;
+                                    $cellDataFormula = substr($cellDataFormula, strpos($cellDataFormula, ':=')+1);
+                                    $temp = explode('"', $cellDataFormula);
+                                    $tKey = false;
+                                    foreach ($temp as &$value) {
+                                        //    Only replace in alternate array entries (i.e. non-quoted blocks)
+                                        if ($tKey = !$tKey) {
+                                            $value = preg_replace('/\[([^\.]+)\.([^\.]+):\.([^\.]+)\]/Ui', '$1!$2:$3', $value);    //  Cell range reference in another sheet
+                                            $value = preg_replace('/\[([^\.]+)\.([^\.]+)\]/Ui', '$1!$2', $value);       //  Cell reference in another sheet
+                                            $value = preg_replace('/\[\.([^\.]+):\.([^\.]+)\]/Ui', '$1:$2', $value);    //  Cell range reference
+                                            $value = preg_replace('/\[\.([^\.]+)\]/Ui', '$1', $value);                  //  Simple cell reference
+                                            $value = PHPExcel_Calculation::translateSeparator(';', ',', $value, $inBraces);
+                                        }
+                                    }
+                                    unset($value);
+                                    //    Then rebuild the formula string
+                                    $cellDataFormula = implode('"', $temp);
+//                                    echo 'Adjusted Formula: ', $cellDataFormula, PHP_EOL;
+                                }
+
+                                $colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ? $cellDataTableAttributes['number-columns-repeated'] : 1;
+                                if ($type !== null) {
+                                    for ($i = 0; $i < $colRepeats; ++$i) {
+                                        if ($i > 0) {
+                                            ++$columnID;
+                                        }
+                                        if ($type !== PHPExcel_Cell_DataType::TYPE_NULL) {
+                                            for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) {
+                                                $rID = $rowID + $rowAdjust;
+                                                $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $dataValue), $type);
+                                                if ($hasCalculatedValue) {
+//                                                    echo 'Forumla result is '.$dataValue.'<br />';
+                                                    $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setCalculatedValue($dataValue);
+                                                }
+                                                if ($formatting !== null) {
+                                                    $objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode($formatting);
+                                                } else {
+                                                    $objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_GENERAL);
+                                                }
+                                                if ($hyperlink !== null) {
+                                                    $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->getHyperlink()->setUrl($hyperlink);
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+
+                                //    Merged cells
+                                if ((isset($cellDataTableAttributes['number-columns-spanned'])) || (isset($cellDataTableAttributes['number-rows-spanned']))) {
+                                    if (($type !== PHPExcel_Cell_DataType::TYPE_NULL) || (!$this->readDataOnly)) {
+                                        $columnTo = $columnID;
+                                        if (isset($cellDataTableAttributes['number-columns-spanned'])) {
+                                            $columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cellDataTableAttributes['number-columns-spanned'] -2);
+                                        }
+                                        $rowTo = $rowID;
+                                        if (isset($cellDataTableAttributes['number-rows-spanned'])) {
+                                            $rowTo = $rowTo + $cellDataTableAttributes['number-rows-spanned'] - 1;
+                                        }
+                                        $cellRange = $columnID.$rowID.':'.$columnTo.$rowTo;
+                                        $objPHPExcel->getActiveSheet()->mergeCells($cellRange);
+                                    }
+                                }
+
+                                ++$columnID;
+                            }
+                            $rowID += $rowRepeats;
+                            break;
+                    }
+                }
+                ++$worksheetID;
+            }
+        }
+
+        // Return
+        return $objPHPExcel;
+    }
+
+    private function parseRichText($is = '')
+    {
+        $value = new PHPExcel_RichText();
+
+        $value->createText($is);
+
+        return $value;
+    }
+}

+ 0 - 0
backend/RTP/extend/excel/PHPExcel/Reader/SYLK.php


Some files were not shown because too many files changed in this diff