diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/CodePage.php b/includes/PHPExcel/Classes/PHPExcel/Shared/CodePage.php
new file mode 100644
index 0000000..89e2d19
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/CodePage.php
@@ -0,0 +1,106 @@
+ 'January',
+ 'Feb' => 'February',
+ 'Mar' => 'March',
+ 'Apr' => 'April',
+ 'May' => 'May',
+ 'Jun' => 'June',
+ 'Jul' => 'July',
+ 'Aug' => 'August',
+ 'Sep' => 'September',
+ 'Oct' => 'October',
+ 'Nov' => 'November',
+ 'Dec' => 'December',
+ );
+
+ /*
+ * Names of the months of the year, indexed by shortname
+ * Planned usage for locale settings
+ *
+ * @public
+ * @var string[]
+ */
+ public static $_numberSuffixes = array( 'st',
+ 'nd',
+ 'rd',
+ 'th',
+ );
+
+ /*
+ * Base calendar year to use for calculations
+ *
+ * @private
+ * @var int
+ */
+ protected static $_excelBaseDate = self::CALENDAR_WINDOWS_1900;
+
+ /**
+ * Set the Excel calendar (Windows 1900 or Mac 1904)
+ *
+ * @param integer $baseDate Excel base date (1900 or 1904)
+ * @return boolean Success or failure
+ */
+ public static function setExcelCalendar($baseDate) {
+ if (($baseDate == self::CALENDAR_WINDOWS_1900) ||
+ ($baseDate == self::CALENDAR_MAC_1904)) {
+ self::$_excelBaseDate = $baseDate;
+ return TRUE;
+ }
+ return FALSE;
+ } // function setExcelCalendar()
+
+
+ /**
+ * Return the Excel calendar (Windows 1900 or Mac 1904)
+ *
+ * @return integer Excel base date (1900 or 1904)
+ */
+ public static function getExcelCalendar() {
+ return self::$_excelBaseDate;
+ } // function getExcelCalendar()
+
+
+ /**
+ * Convert a date from Excel to PHP
+ *
+ * @param long $dateValue Excel date/time value
+ * @param boolean $adjustToTimezone Flag indicating whether $dateValue should be treated as
+ * a UST timestamp, or adjusted to UST
+ * @param string $timezone The timezone for finding the adjustment from UST
+ * @return long PHP serialized date/time
+ */
+ public static function ExcelToPHP($dateValue = 0, $adjustToTimezone = FALSE, $timezone = NULL) {
+ if (self::$_excelBaseDate == self::CALENDAR_WINDOWS_1900) {
+ $my_excelBaseDate = 25569;
+ // Adjust for the spurious 29-Feb-1900 (Day 60)
+ if ($dateValue < 60) {
+ --$my_excelBaseDate;
+ }
+ } else {
+ $my_excelBaseDate = 24107;
+ }
+
+ // Perform conversion
+ if ($dateValue >= 1) {
+ $utcDays = $dateValue - $my_excelBaseDate;
+ $returnValue = round($utcDays * 86400);
+ if (($returnValue <= PHP_INT_MAX) && ($returnValue >= -PHP_INT_MAX)) {
+ $returnValue = (integer) $returnValue;
+ }
+ } else {
+ $hours = round($dateValue * 24);
+ $mins = round($dateValue * 1440) - round($hours * 60);
+ $secs = round($dateValue * 86400) - round($hours * 3600) - round($mins * 60);
+ $returnValue = (integer) gmmktime($hours, $mins, $secs);
+ }
+
+ $timezoneAdjustment = ($adjustToTimezone) ?
+ PHPExcel_Shared_TimeZone::getTimezoneAdjustment($timezone, $returnValue) :
+ 0;
+
+ // Return
+ return $returnValue + $timezoneAdjustment;
+ } // function ExcelToPHP()
+
+
+ /**
+ * Convert a date from Excel to a PHP Date/Time object
+ *
+ * @param integer $dateValue Excel date/time value
+ * @return DateTime PHP date/time object
+ */
+ public static function ExcelToPHPObject($dateValue = 0) {
+ $dateTime = self::ExcelToPHP($dateValue);
+ $days = floor($dateTime / 86400);
+ $time = round((($dateTime / 86400) - $days) * 86400);
+ $hours = round($time / 3600);
+ $minutes = round($time / 60) - ($hours * 60);
+ $seconds = round($time) - ($hours * 3600) - ($minutes * 60);
+
+ $dateObj = date_create('1-Jan-1970+'.$days.' days');
+ $dateObj->setTime($hours,$minutes,$seconds);
+
+ return $dateObj;
+ } // function ExcelToPHPObject()
+
+
+ /**
+ * Convert a date from PHP to Excel
+ *
+ * @param mixed $dateValue PHP serialized date/time or date object
+ * @param boolean $adjustToTimezone Flag indicating whether $dateValue should be treated as
+ * a UST timestamp, or adjusted to UST
+ * @param string $timezone The timezone for finding the adjustment from UST
+ * @return mixed Excel date/time value
+ * or boolean FALSE on failure
+ */
+ public static function PHPToExcel($dateValue = 0, $adjustToTimezone = FALSE, $timezone = NULL) {
+ $saveTimeZone = date_default_timezone_get();
+ date_default_timezone_set('UTC');
+ $retValue = FALSE;
+ if ((is_object($dateValue)) && ($dateValue instanceof DateTime)) {
+ $retValue = self::FormattedPHPToExcel( $dateValue->format('Y'), $dateValue->format('m'), $dateValue->format('d'),
+ $dateValue->format('H'), $dateValue->format('i'), $dateValue->format('s')
+ );
+ } elseif (is_numeric($dateValue)) {
+ $retValue = self::FormattedPHPToExcel( date('Y',$dateValue), date('m',$dateValue), date('d',$dateValue),
+ date('H',$dateValue), date('i',$dateValue), date('s',$dateValue)
+ );
+ }
+ date_default_timezone_set($saveTimeZone);
+
+ return $retValue;
+ } // function PHPToExcel()
+
+
+ /**
+ * FormattedPHPToExcel
+ *
+ * @param long $year
+ * @param long $month
+ * @param long $day
+ * @param long $hours
+ * @param long $minutes
+ * @param long $seconds
+ * @return long Excel date/time value
+ */
+ public static function FormattedPHPToExcel($year, $month, $day, $hours=0, $minutes=0, $seconds=0) {
+ if (self::$_excelBaseDate == self::CALENDAR_WINDOWS_1900) {
+ //
+ // Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
+ // This affects every date following 28th February 1900
+ //
+ $excel1900isLeapYear = TRUE;
+ if (($year == 1900) && ($month <= 2)) { $excel1900isLeapYear = FALSE; }
+ $my_excelBaseDate = 2415020;
+ } else {
+ $my_excelBaseDate = 2416481;
+ $excel1900isLeapYear = FALSE;
+ }
+
+ // Julian base date Adjustment
+ if ($month > 2) {
+ $month -= 3;
+ } else {
+ $month += 9;
+ --$year;
+ }
+
+ // Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
+ $century = substr($year,0,2);
+ $decade = substr($year,2,2);
+ $excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $my_excelBaseDate + $excel1900isLeapYear;
+
+ $excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400;
+
+ return (float) $excelDate + $excelTime;
+ } // function FormattedPHPToExcel()
+
+
+ /**
+ * Is a given cell a date/time?
+ *
+ * @param PHPExcel_Cell $pCell
+ * @return boolean
+ */
+ public static function isDateTime(PHPExcel_Cell $pCell) {
+ return self::isDateTimeFormat(
+ $pCell->getWorksheet()->getStyle(
+ $pCell->getCoordinate()
+ )->getNumberFormat()
+ );
+ } // function isDateTime()
+
+
+ /**
+ * Is a given number format a date/time?
+ *
+ * @param PHPExcel_Style_NumberFormat $pFormat
+ * @return boolean
+ */
+ public static function isDateTimeFormat(PHPExcel_Style_NumberFormat $pFormat) {
+ return self::isDateTimeFormatCode($pFormat->getFormatCode());
+ } // function isDateTimeFormat()
+
+
+ private static $possibleDateFormatCharacters = 'eymdHs';
+
+ /**
+ * Is a given number format code a date/time?
+ *
+ * @param string $pFormatCode
+ * @return boolean
+ */
+ public static function isDateTimeFormatCode($pFormatCode = '') {
+ if (strtolower($pFormatCode) === strtolower(PHPExcel_Style_NumberFormat::FORMAT_GENERAL))
+ // "General" contains an epoch letter 'e', so we trap for it explicitly here (case-insensitive check)
+ return FALSE;
+ if (preg_match('/[0#]E[+-]0/i', $pFormatCode))
+ // Scientific format
+ return FALSE;
+ // Switch on formatcode
+ switch ($pFormatCode) {
+ // Explicitly defined date formats
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYSLASH:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYMINUS:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMMINUS:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_MYMINUS:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME1:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME2:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME5:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME6:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME7:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME8:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDDSLASH:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX14:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22:
+ return TRUE;
+ }
+
+ // Typically number, currency or accounting (or occasionally fraction) formats
+ if ((substr($pFormatCode,0,1) == '_') || (substr($pFormatCode,0,2) == '0 ')) {
+ return FALSE;
+ }
+ // Try checking for any of the date formatting characters that don't appear within square braces
+ if (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$pFormatCode)) {
+ // We might also have a format mask containing quoted strings...
+ // we don't want to test for any of our characters within the quoted blocks
+ if (strpos($pFormatCode,'"') !== FALSE) {
+ $segMatcher = FALSE;
+ foreach(explode('"',$pFormatCode) as $subVal) {
+ // Only test in alternate array entries (the non-quoted blocks)
+ if (($segMatcher = !$segMatcher) &&
+ (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$subVal))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ // No date...
+ return FALSE;
+ } // function isDateTimeFormatCode()
+
+
+ /**
+ * Convert a date/time string to Excel time
+ *
+ * @param string $dateValue Examples: '2009-12-31', '2009-12-31 15:59', '2009-12-31 15:59:10'
+ * @return float|FALSE Excel date/time serial value
+ */
+ public static function stringToExcel($dateValue = '') {
+ if (strlen($dateValue) < 2)
+ return FALSE;
+ if (!preg_match('/^(\d{1,4}[ \.\/\-][A-Z]{3,9}([ \.\/\-]\d{1,4})?|[A-Z]{3,9}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?|\d{1,4}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?)( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/iu', $dateValue))
+ return FALSE;
+
+ $dateValueNew = PHPExcel_Calculation_DateTime::DATEVALUE($dateValue);
+
+ if ($dateValueNew === PHPExcel_Calculation_Functions::VALUE()) {
+ return FALSE;
+ } else {
+ if (strpos($dateValue, ':') !== FALSE) {
+ $timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($dateValue);
+ if ($timeValue === PHPExcel_Calculation_Functions::VALUE()) {
+ return FALSE;
+ }
+ $dateValueNew += $timeValue;
+ }
+ return $dateValueNew;
+ }
+
+
+ }
+
+ public static function monthStringToNumber($month) {
+ $monthIndex = 1;
+ foreach(self::$_monthNames as $shortMonthName => $longMonthName) {
+ if (($month === $longMonthName) || ($month === $shortMonthName)) {
+ return $monthIndex;
+ }
+ ++$monthIndex;
+ }
+ return $month;
+ }
+
+ public static function dayStringToNumber($day) {
+ $strippedDayValue = (str_replace(self::$_numberSuffixes,'',$day));
+ if (is_numeric($strippedDayValue)) {
+ return $strippedDayValue;
+ }
+ return $day;
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/Drawing.php b/includes/PHPExcel/Classes/PHPExcel/Shared/Drawing.php
new file mode 100644
index 0000000..dbff74a
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/Drawing.php
@@ -0,0 +1,272 @@
+getName();
+ $size = $pDefaultFont->getSize();
+
+ if (isset(PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size])) {
+ // Exact width can be determined
+ $colWidth = $pValue
+ * PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['width']
+ / PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['px'];
+ } else {
+ // We don't have data for this particular font and size, use approximation by
+ // extrapolating from Calibri 11
+ $colWidth = $pValue * 11
+ * PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['width']
+ / PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['px'] / $size;
+ }
+
+ return $colWidth;
+ }
+
+ /**
+ * Convert column width from (intrinsic) Excel units to pixels
+ *
+ * @param float $pValue Value in cell dimension
+ * @param PHPExcel_Style_Font $pDefaultFont Default font of the workbook
+ * @return int Value in pixels
+ */
+ public static function cellDimensionToPixels($pValue = 0, PHPExcel_Style_Font $pDefaultFont) {
+ // Font name and size
+ $name = $pDefaultFont->getName();
+ $size = $pDefaultFont->getSize();
+
+ if (isset(PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size])) {
+ // Exact width can be determined
+ $colWidth = $pValue
+ * PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['px']
+ / PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['width'];
+
+ } else {
+ // We don't have data for this particular font and size, use approximation by
+ // extrapolating from Calibri 11
+ $colWidth = $pValue * $size
+ * PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['px']
+ / PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['width'] / 11;
+ }
+
+ // Round pixels to closest integer
+ $colWidth = (int) round($colWidth);
+
+ return $colWidth;
+ }
+
+ /**
+ * Convert pixels to points
+ *
+ * @param int $pValue Value in pixels
+ * @return int Value in points
+ */
+ public static function pixelsToPoints($pValue = 0) {
+ return $pValue * 0.67777777;
+ }
+
+ /**
+ * Convert points to pixels
+ *
+ * @param int $pValue Value in points
+ * @return int Value in pixels
+ */
+ public static function pointsToPixels($pValue = 0) {
+ if ($pValue != 0) {
+ return (int) ceil($pValue * 1.333333333);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Convert degrees to angle
+ *
+ * @param int $pValue Degrees
+ * @return int Angle
+ */
+ public static function degreesToAngle($pValue = 0) {
+ return (int)round($pValue * 60000);
+ }
+
+ /**
+ * Convert angle to degrees
+ *
+ * @param int $pValue Angle
+ * @return int Degrees
+ */
+ public static function angleToDegrees($pValue = 0) {
+ if ($pValue != 0) {
+ return round($pValue / 60000);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Create a new image from file. By alexander at alexauto dot nl
+ *
+ * @link http://www.php.net/manual/en/function.imagecreatefromwbmp.php#86214
+ * @param string $filename Path to Windows DIB (BMP) image
+ * @return resource
+ */
+ public static function imagecreatefrombmp($p_sFile)
+ {
+ // Load the image into a string
+ $file = fopen($p_sFile,"rb");
+ $read = fread($file,10);
+ while(!feof($file)&&($read<>""))
+ $read .= fread($file,1024);
+
+ $temp = unpack("H*",$read);
+ $hex = $temp[1];
+ $header = substr($hex,0,108);
+
+ // Process the header
+ // Structure: http://www.fastgraph.com/help/bmp_header_format.html
+ if (substr($header,0,4)=="424d")
+ {
+ // Cut it in parts of 2 bytes
+ $header_parts = str_split($header,2);
+
+ // Get the width 4 bytes
+ $width = hexdec($header_parts[19].$header_parts[18]);
+
+ // Get the height 4 bytes
+ $height = hexdec($header_parts[23].$header_parts[22]);
+
+ // Unset the header params
+ unset($header_parts);
+ }
+
+ // Define starting X and Y
+ $x = 0;
+ $y = 1;
+
+ // Create newimage
+ $image = imagecreatetruecolor($width,$height);
+
+ // Grab the body from the image
+ $body = substr($hex,108);
+
+ // Calculate if padding at the end-line is needed
+ // Divided by two to keep overview.
+ // 1 byte = 2 HEX-chars
+ $body_size = (strlen($body)/2);
+ $header_size = ($width*$height);
+
+ // Use end-line padding? Only when needed
+ $usePadding = ($body_size>($header_size*3)+4);
+
+ // Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
+ // Calculate the next DWORD-position in the body
+ for ($i=0;$i<$body_size;$i+=3)
+ {
+ // Calculate line-ending and padding
+ if ($x>=$width)
+ {
+ // If padding needed, ignore image-padding
+ // Shift i to the ending of the current 32-bit-block
+ if ($usePadding)
+ $i += $width%4;
+
+ // Reset horizontal position
+ $x = 0;
+
+ // Raise the height-position (bottom-up)
+ $y++;
+
+ // Reached the image-height? Break the for-loop
+ if ($y>$height)
+ break;
+ }
+
+ // Calculation of the RGB-pixel (defined as BGR in image-data)
+ // Define $i_pos as absolute position in the body
+ $i_pos = $i*2;
+ $r = hexdec($body[$i_pos+4].$body[$i_pos+5]);
+ $g = hexdec($body[$i_pos+2].$body[$i_pos+3]);
+ $b = hexdec($body[$i_pos].$body[$i_pos+1]);
+
+ // Calculate and draw the pixel
+ $color = imagecolorallocate($image,$r,$g,$b);
+ imagesetpixel($image,$x,$height-$y,$color);
+
+ // Raise the horizontal position
+ $x++;
+ }
+
+ // Unset the body / free the memory
+ unset($body);
+
+ // Return image-object
+ return $image;
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/Escher.php b/includes/PHPExcel/Classes/PHPExcel/Shared/Escher.php
new file mode 100644
index 0000000..ddf68c6
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/Escher.php
@@ -0,0 +1,91 @@
+_dggContainer;
+ }
+
+ /**
+ * Set Drawing Group Container
+ *
+ * @param PHPExcel_Shared_Escher_DggContainer $dggContainer
+ */
+ public function setDggContainer($dggContainer)
+ {
+ return $this->_dggContainer = $dggContainer;
+ }
+
+ /**
+ * Get Drawing Container
+ *
+ * @return PHPExcel_Shared_Escher_DgContainer
+ */
+ public function getDgContainer()
+ {
+ return $this->_dgContainer;
+ }
+
+ /**
+ * Set Drawing Container
+ *
+ * @param PHPExcel_Shared_Escher_DgContainer $dgContainer
+ */
+ public function setDgContainer($dgContainer)
+ {
+ return $this->_dgContainer = $dgContainer;
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/Excel5.php b/includes/PHPExcel/Classes/PHPExcel/Shared/Excel5.php
new file mode 100644
index 0000000..3caf675
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/Excel5.php
@@ -0,0 +1,317 @@
+getParent()->getDefaultStyle()->getFont();
+
+ $columnDimensions = $sheet->getColumnDimensions();
+
+ // first find the true column width in pixels (uncollapsed and unhidden)
+ if ( isset($columnDimensions[$col]) and $columnDimensions[$col]->getWidth() != -1 ) {
+
+ // then we have column dimension with explicit width
+ $columnDimension = $columnDimensions[$col];
+ $width = $columnDimension->getWidth();
+ $pixelWidth = PHPExcel_Shared_Drawing::cellDimensionToPixels($width, $font);
+
+ } else if ($sheet->getDefaultColumnDimension()->getWidth() != -1) {
+
+ // then we have default column dimension with explicit width
+ $defaultColumnDimension = $sheet->getDefaultColumnDimension();
+ $width = $defaultColumnDimension->getWidth();
+ $pixelWidth = PHPExcel_Shared_Drawing::cellDimensionToPixels($width, $font);
+
+ } else {
+
+ // we don't even have any default column dimension. Width depends on default font
+ $pixelWidth = PHPExcel_Shared_Font::getDefaultColumnWidthByFont($font, true);
+ }
+
+ // now find the effective column width in pixels
+ if (isset($columnDimensions[$col]) and !$columnDimensions[$col]->getVisible()) {
+ $effectivePixelWidth = 0;
+ } else {
+ $effectivePixelWidth = $pixelWidth;
+ }
+
+ return $effectivePixelWidth;
+ }
+
+ /**
+ * Convert the height of a cell from user's units to pixels. By interpolation
+ * the relationship is: y = 4/3x. If the height hasn't been set by the user we
+ * use the default value. If the row is hidden we use a value of zero.
+ *
+ * @param PHPExcel_Worksheet $sheet The sheet
+ * @param integer $row The row index (1-based)
+ * @return integer The width in pixels
+ */
+ public static function sizeRow($sheet, $row = 1)
+ {
+ // default font of the workbook
+ $font = $sheet->getParent()->getDefaultStyle()->getFont();
+
+ $rowDimensions = $sheet->getRowDimensions();
+
+ // first find the true row height in pixels (uncollapsed and unhidden)
+ if ( isset($rowDimensions[$row]) and $rowDimensions[$row]->getRowHeight() != -1) {
+
+ // then we have a row dimension
+ $rowDimension = $rowDimensions[$row];
+ $rowHeight = $rowDimension->getRowHeight();
+ $pixelRowHeight = (int) ceil(4 * $rowHeight / 3); // here we assume Arial 10
+
+ } else if ($sheet->getDefaultRowDimension()->getRowHeight() != -1) {
+
+ // then we have a default row dimension with explicit height
+ $defaultRowDimension = $sheet->getDefaultRowDimension();
+ $rowHeight = $defaultRowDimension->getRowHeight();
+ $pixelRowHeight = PHPExcel_Shared_Drawing::pointsToPixels($rowHeight);
+
+ } else {
+
+ // we don't even have any default row dimension. Height depends on default font
+ $pointRowHeight = PHPExcel_Shared_Font::getDefaultRowHeightByFont($font);
+ $pixelRowHeight = PHPExcel_Shared_Font::fontSizeToPixels($pointRowHeight);
+
+ }
+
+ // now find the effective row height in pixels
+ if ( isset($rowDimensions[$row]) and !$rowDimensions[$row]->getVisible() ) {
+ $effectivePixelRowHeight = 0;
+ } else {
+ $effectivePixelRowHeight = $pixelRowHeight;
+ }
+
+ return $effectivePixelRowHeight;
+ }
+
+ /**
+ * Get the horizontal distance in pixels between two anchors
+ * The distanceX is found as sum of all the spanning columns widths minus correction for the two offsets
+ *
+ * @param PHPExcel_Worksheet $sheet
+ * @param string $startColumn
+ * @param integer $startOffsetX Offset within start cell measured in 1/1024 of the cell width
+ * @param string $endColumn
+ * @param integer $endOffsetX Offset within end cell measured in 1/1024 of the cell width
+ * @return integer Horizontal measured in pixels
+ */
+ public static function getDistanceX(PHPExcel_Worksheet $sheet, $startColumn = 'A', $startOffsetX = 0, $endColumn = 'A', $endOffsetX = 0)
+ {
+ $distanceX = 0;
+
+ // add the widths of the spanning columns
+ $startColumnIndex = PHPExcel_Cell::columnIndexFromString($startColumn) - 1; // 1-based
+ $endColumnIndex = PHPExcel_Cell::columnIndexFromString($endColumn) - 1; // 1-based
+ for ($i = $startColumnIndex; $i <= $endColumnIndex; ++$i) {
+ $distanceX += self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($i));
+ }
+
+ // correct for offsetX in startcell
+ $distanceX -= (int) floor(self::sizeCol($sheet, $startColumn) * $startOffsetX / 1024);
+
+ // correct for offsetX in endcell
+ $distanceX -= (int) floor(self::sizeCol($sheet, $endColumn) * (1 - $endOffsetX / 1024));
+
+ return $distanceX;
+ }
+
+ /**
+ * Get the vertical distance in pixels between two anchors
+ * The distanceY is found as sum of all the spanning rows minus two offsets
+ *
+ * @param PHPExcel_Worksheet $sheet
+ * @param integer $startRow (1-based)
+ * @param integer $startOffsetY Offset within start cell measured in 1/256 of the cell height
+ * @param integer $endRow (1-based)
+ * @param integer $endOffsetY Offset within end cell measured in 1/256 of the cell height
+ * @return integer Vertical distance measured in pixels
+ */
+ public static function getDistanceY(PHPExcel_Worksheet $sheet, $startRow = 1, $startOffsetY = 0, $endRow = 1, $endOffsetY = 0)
+ {
+ $distanceY = 0;
+
+ // add the widths of the spanning rows
+ for ($row = $startRow; $row <= $endRow; ++$row) {
+ $distanceY += self::sizeRow($sheet, $row);
+ }
+
+ // correct for offsetX in startcell
+ $distanceY -= (int) floor(self::sizeRow($sheet, $startRow) * $startOffsetY / 256);
+
+ // correct for offsetX in endcell
+ $distanceY -= (int) floor(self::sizeRow($sheet, $endRow) * (1 - $endOffsetY / 256));
+
+ return $distanceY;
+ }
+
+ /**
+ * Convert 1-cell anchor coordinates to 2-cell anchor coordinates
+ * This function is ported from PEAR Spreadsheet_Writer_Excel with small modifications
+ *
+ * Calculate the vertices that define the position of the image as required by
+ * the OBJ record.
+ *
+ * +------------+------------+
+ * | A | B |
+ * +-----+------------+------------+
+ * | |(x1,y1) | |
+ * | 1 |(A1)._______|______ |
+ * | | | | |
+ * | | | | |
+ * +-----+----| BITMAP |-----+
+ * | | | | |
+ * | 2 | |______________. |
+ * | | | (B2)|
+ * | | | (x2,y2)|
+ * +---- +------------+------------+
+ *
+ * Example of a bitmap that covers some of the area from cell A1 to cell B2.
+ *
+ * Based on the width and height of the bitmap we need to calculate 8 vars:
+ * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
+ * The width and height of the cells are also variable and have to be taken into
+ * account.
+ * The values of $col_start and $row_start are passed in from the calling
+ * function. The values of $col_end and $row_end are calculated by subtracting
+ * the width and height of the bitmap from the width and height of the
+ * underlying cells.
+ * The vertices are expressed as a percentage of the underlying cell width as
+ * follows (rhs values are in pixels):
+ *
+ * x1 = X / W *1024
+ * y1 = Y / H *256
+ * x2 = (X-1) / W *1024
+ * y2 = (Y-1) / H *256
+ *
+ * Where: X is distance from the left side of the underlying cell
+ * Y is distance from the top of the underlying cell
+ * W is the width of the cell
+ * H is the height of the cell
+ *
+ * @param PHPExcel_Worksheet $sheet
+ * @param string $coordinates E.g. 'A1'
+ * @param integer $offsetX Horizontal offset in pixels
+ * @param integer $offsetY Vertical offset in pixels
+ * @param integer $width Width in pixels
+ * @param integer $height Height in pixels
+ * @return array
+ */
+ public static function oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height)
+ {
+ list($column, $row) = PHPExcel_Cell::coordinateFromString($coordinates);
+ $col_start = PHPExcel_Cell::columnIndexFromString($column) - 1;
+ $row_start = $row - 1;
+
+ $x1 = $offsetX;
+ $y1 = $offsetY;
+
+ // Initialise end cell to the same as the start cell
+ $col_end = $col_start; // Col containing lower right corner of object
+ $row_end = $row_start; // Row containing bottom right corner of object
+
+ // Zero the specified offset if greater than the cell dimensions
+ if ($x1 >= self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_start))) {
+ $x1 = 0;
+ }
+ if ($y1 >= self::sizeRow($sheet, $row_start + 1)) {
+ $y1 = 0;
+ }
+
+ $width = $width + $x1 -1;
+ $height = $height + $y1 -1;
+
+ // Subtract the underlying cell widths to find the end cell of the image
+ while ($width >= self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end))) {
+ $width -= self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end));
+ ++$col_end;
+ }
+
+ // Subtract the underlying cell heights to find the end cell of the image
+ while ($height >= self::sizeRow($sheet, $row_end + 1)) {
+ $height -= self::sizeRow($sheet, $row_end + 1);
+ ++$row_end;
+ }
+
+ // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
+ // with zero height or width.
+ if (self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_start)) == 0) {
+ return;
+ }
+ if (self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end)) == 0) {
+ return;
+ }
+ if (self::sizeRow($sheet, $row_start + 1) == 0) {
+ return;
+ }
+ if (self::sizeRow($sheet, $row_end + 1) == 0) {
+ return;
+ }
+
+ // Convert the pixel values to the percentage value expected by Excel
+ $x1 = $x1 / self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_start)) * 1024;
+ $y1 = $y1 / self::sizeRow($sheet, $row_start + 1) * 256;
+ $x2 = ($width + 1) / self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end)) * 1024; // Distance to right side of object
+ $y2 = ($height + 1) / self::sizeRow($sheet, $row_end + 1) * 256; // Distance to bottom of object
+
+ $startCoordinates = PHPExcel_Cell::stringFromColumnIndex($col_start) . ($row_start + 1);
+ $endCoordinates = PHPExcel_Cell::stringFromColumnIndex($col_end) . ($row_end + 1);
+
+ $twoAnchor = array(
+ 'startCoordinates' => $startCoordinates,
+ 'startOffsetX' => $x1,
+ 'startOffsetY' => $y1,
+ 'endCoordinates' => $endCoordinates,
+ 'endOffsetX' => $x2,
+ 'endOffsetY' => $y2,
+ );
+
+ return $twoAnchor;
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/File.php b/includes/PHPExcel/Classes/PHPExcel/Shared/File.php
new file mode 100644
index 0000000..52c9b97
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/File.php
@@ -0,0 +1,178 @@
+open($zipFile) === true) {
+ $returnValue = ($zip->getFromName($archiveFile) !== false);
+ $zip->close();
+ return $returnValue;
+ } else {
+ return false;
+ }
+ } else {
+ // Regular file_exists
+ return file_exists($pFilename);
+ }
+ }
+
+ /**
+ * Returns canonicalized absolute pathname, also for ZIP archives
+ *
+ * @param string $pFilename
+ * @return string
+ */
+ public static function realpath($pFilename) {
+ // Returnvalue
+ $returnValue = '';
+
+ // Try using realpath()
+ if (file_exists($pFilename)) {
+ $returnValue = realpath($pFilename);
+ }
+
+ // Found something?
+ if ($returnValue == '' || ($returnValue === NULL)) {
+ $pathArray = explode('/' , $pFilename);
+ while(in_array('..', $pathArray) && $pathArray[0] != '..') {
+ for ($i = 0; $i < count($pathArray); ++$i) {
+ if ($pathArray[$i] == '..' && $i > 0) {
+ unset($pathArray[$i]);
+ unset($pathArray[$i - 1]);
+ break;
+ }
+ }
+ }
+ $returnValue = implode('/', $pathArray);
+ }
+
+ // Return
+ return $returnValue;
+ }
+
+ /**
+ * Get the systems temporary directory.
+ *
+ * @return string
+ */
+ public static function sys_get_temp_dir()
+ {
+ if (self::$_useUploadTempDirectory) {
+ // use upload-directory when defined to allow running on environments having very restricted
+ // open_basedir configs
+ if (ini_get('upload_tmp_dir') !== FALSE) {
+ if ($temp = ini_get('upload_tmp_dir')) {
+ if (file_exists($temp))
+ return realpath($temp);
+ }
+ }
+ }
+
+ // sys_get_temp_dir is only available since PHP 5.2.1
+ // http://php.net/manual/en/function.sys-get-temp-dir.php#94119
+ if ( !function_exists('sys_get_temp_dir')) {
+ if ($temp = getenv('TMP') ) {
+ if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); }
+ }
+ if ($temp = getenv('TEMP') ) {
+ if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); }
+ }
+ if ($temp = getenv('TMPDIR') ) {
+ if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); }
+ }
+
+ // trick for creating a file in system's temporary dir
+ // without knowing the path of the system's temporary dir
+ $temp = tempnam(__FILE__, '');
+ if (file_exists($temp)) {
+ unlink($temp);
+ return realpath(dirname($temp));
+ }
+
+ return null;
+ }
+
+ // use ordinary built-in PHP function
+ // There should be no problem with the 5.2.4 Suhosin realpath() bug, because this line should only
+ // be called if we're running 5.2.1 or earlier
+ return realpath(sys_get_temp_dir());
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/Font.php b/includes/PHPExcel/Classes/PHPExcel/Shared/Font.php
new file mode 100644
index 0000000..8e5b27b
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/Font.php
@@ -0,0 +1,773 @@
+ array(
+ 1 => array('px' => 24, 'width' => 12.00000000),
+ 2 => array('px' => 24, 'width' => 12.00000000),
+ 3 => array('px' => 32, 'width' => 10.66406250),
+ 4 => array('px' => 32, 'width' => 10.66406250),
+ 5 => array('px' => 40, 'width' => 10.00000000),
+ 6 => array('px' => 48, 'width' => 9.59765625),
+ 7 => array('px' => 48, 'width' => 9.59765625),
+ 8 => array('px' => 56, 'width' => 9.33203125),
+ 9 => array('px' => 64, 'width' => 9.14062500),
+ 10 => array('px' => 64, 'width' => 9.14062500),
+ ),
+ 'Calibri' => array(
+ 1 => array('px' => 24, 'width' => 12.00000000),
+ 2 => array('px' => 24, 'width' => 12.00000000),
+ 3 => array('px' => 32, 'width' => 10.66406250),
+ 4 => array('px' => 32, 'width' => 10.66406250),
+ 5 => array('px' => 40, 'width' => 10.00000000),
+ 6 => array('px' => 48, 'width' => 9.59765625),
+ 7 => array('px' => 48, 'width' => 9.59765625),
+ 8 => array('px' => 56, 'width' => 9.33203125),
+ 9 => array('px' => 56, 'width' => 9.33203125),
+ 10 => array('px' => 64, 'width' => 9.14062500),
+ 11 => array('px' => 64, 'width' => 9.14062500),
+ ),
+ 'Verdana' => array(
+ 1 => array('px' => 24, 'width' => 12.00000000),
+ 2 => array('px' => 24, 'width' => 12.00000000),
+ 3 => array('px' => 32, 'width' => 10.66406250),
+ 4 => array('px' => 32, 'width' => 10.66406250),
+ 5 => array('px' => 40, 'width' => 10.00000000),
+ 6 => array('px' => 48, 'width' => 9.59765625),
+ 7 => array('px' => 48, 'width' => 9.59765625),
+ 8 => array('px' => 64, 'width' => 9.14062500),
+ 9 => array('px' => 72, 'width' => 9.00000000),
+ 10 => array('px' => 72, 'width' => 9.00000000),
+ ),
+ );
+
+ /**
+ * Set autoSize method
+ *
+ * @param string $pValue
+ * @return boolean Success or failure
+ */
+ public static function setAutoSizeMethod($pValue = self::AUTOSIZE_METHOD_APPROX)
+ {
+ if (!in_array($pValue,self::$_autoSizeMethods)) {
+ return FALSE;
+ }
+ self::$autoSizeMethod = $pValue;
+
+ return TRUE;
+ }
+
+ /**
+ * Get autoSize method
+ *
+ * @return string
+ */
+ public static function getAutoSizeMethod()
+ {
+ return self::$autoSizeMethod;
+ }
+
+ /**
+ * Set the path to the folder containing .ttf files. There should be a trailing slash.
+ * Typical locations on variout some platforms:
+ *
+ * - C:/Windows/Fonts/
+ * - /usr/share/fonts/truetype/
+ * - ~/.fonts/
+ *
+ *
+ * @param string $pValue
+ */
+ public static function setTrueTypeFontPath($pValue = '')
+ {
+ self::$trueTypeFontPath = $pValue;
+ }
+
+ /**
+ * Get the path to the folder containing .ttf files.
+ *
+ * @return string
+ */
+ public static function getTrueTypeFontPath()
+ {
+ return self::$trueTypeFontPath;
+ }
+
+ /**
+ * Calculate an (approximate) OpenXML column width, based on font size and text contained
+ *
+ * @param PHPExcel_Style_Font $font Font object
+ * @param PHPExcel_RichText|string $cellText Text to calculate width
+ * @param integer $rotation Rotation angle
+ * @param PHPExcel_Style_Font|NULL $defaultFont Font object
+ * @return integer Column width
+ */
+ public static function calculateColumnWidth(PHPExcel_Style_Font $font, $cellText = '', $rotation = 0, PHPExcel_Style_Font $defaultFont = null) {
+ // If it is rich text, use plain text
+ if ($cellText instanceof PHPExcel_RichText) {
+ $cellText = $cellText->getPlainText();
+ }
+
+ // Special case if there are one or more newline characters ("\n")
+ if (strpos($cellText, "\n") !== false) {
+ $lineTexts = explode("\n", $cellText);
+ $lineWidths = array();
+ foreach ($lineTexts as $lineText) {
+ $lineWidths[] = self::calculateColumnWidth($font, $lineText, $rotation = 0, $defaultFont);
+ }
+ return max($lineWidths); // width of longest line in cell
+ }
+
+ // Try to get the exact text width in pixels
+ $approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX;
+ if (!$approximate) {
+ $columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07);
+ try {
+ // Width of text in pixels excl. padding
+ // and addition because Excel adds some padding, just use approx width of 'n' glyph
+ $columnWidth = self::getTextWidthPixelsExact($cellText, $font, $rotation) + $columnWidthAdjust;
+ } catch (PHPExcel_Exception $e) {
+ $approximate = true;
+ }
+ }
+
+ if ($approximate) {
+ $columnWidthAdjust = self::getTextWidthPixelsApprox('n', $font, 0);
+ // Width of text in pixels excl. padding, approximation
+ // and addition because Excel adds some padding, just use approx width of 'n' glyph
+ $columnWidth = self::getTextWidthPixelsApprox($cellText, $font, $rotation) + $columnWidthAdjust;
+ }
+
+ // Convert from pixel width to column width
+ $columnWidth = PHPExcel_Shared_Drawing::pixelsToCellDimension($columnWidth, $defaultFont);
+
+ // Return
+ return round($columnWidth, 6);
+ }
+
+ /**
+ * Get GD text width in pixels for a string of text in a certain font at a certain rotation angle
+ *
+ * @param string $text
+ * @param PHPExcel_Style_Font
+ * @param int $rotation
+ * @return int
+ * @throws PHPExcel_Exception
+ */
+ public static function getTextWidthPixelsExact($text, PHPExcel_Style_Font $font, $rotation = 0) {
+ if (!function_exists('imagettfbbox')) {
+ throw new PHPExcel_Exception('GD library needs to be enabled');
+ }
+
+ // font size should really be supplied in pixels in GD2,
+ // but since GD2 seems to assume 72dpi, pixels and points are the same
+ $fontFile = self::getTrueTypeFontFileFromFont($font);
+ $textBox = imagettfbbox($font->getSize(), $rotation, $fontFile, $text);
+
+ // Get corners positions
+ $lowerLeftCornerX = $textBox[0];
+// $lowerLeftCornerY = $textBox[1];
+ $lowerRightCornerX = $textBox[2];
+// $lowerRightCornerY = $textBox[3];
+ $upperRightCornerX = $textBox[4];
+// $upperRightCornerY = $textBox[5];
+ $upperLeftCornerX = $textBox[6];
+// $upperLeftCornerY = $textBox[7];
+
+ // Consider the rotation when calculating the width
+ $textWidth = max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
+
+ return $textWidth;
+ }
+
+ /**
+ * Get approximate width in pixels for a string of text in a certain font at a certain rotation angle
+ *
+ * @param string $columnText
+ * @param PHPExcel_Style_Font $font
+ * @param int $rotation
+ * @return int Text width in pixels (no padding added)
+ */
+ public static function getTextWidthPixelsApprox($columnText, PHPExcel_Style_Font $font = null, $rotation = 0)
+ {
+ $fontName = $font->getName();
+ $fontSize = $font->getSize();
+
+ // Calculate column width in pixels. We assume fixed glyph width. Result varies with font name and size.
+ switch ($fontName) {
+ case 'Calibri':
+ // value 8.26 was found via interpolation by inspecting real Excel files with Calibri 11 font.
+ $columnWidth = (int) (8.26 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
+ break;
+
+ case 'Arial':
+ // value 7 was found via interpolation by inspecting real Excel files with Arial 10 font.
+// $columnWidth = (int) (7 * PHPExcel_Shared_String::CountCharacters($columnText));
+ // value 8 was set because of experience in different exports at Arial 10 font.
+ $columnWidth = (int) (8 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
+ break;
+
+ case 'Verdana':
+ // value 8 was found via interpolation by inspecting real Excel files with Verdana 10 font.
+ $columnWidth = (int) (8 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
+ break;
+
+ default:
+ // just assume Calibri
+ $columnWidth = (int) (8.26 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
+ break;
+ }
+
+ // Calculate approximate rotated column width
+ if ($rotation !== 0) {
+ if ($rotation == -165) {
+ // stacked text
+ $columnWidth = 4; // approximation
+ } else {
+ // rotated text
+ $columnWidth = $columnWidth * cos(deg2rad($rotation))
+ + $fontSize * abs(sin(deg2rad($rotation))) / 5; // approximation
+ }
+ }
+
+ // pixel width is an integer
+ return (int) $columnWidth;
+ }
+
+ /**
+ * Calculate an (approximate) pixel size, based on a font points size
+ *
+ * @param int $fontSizeInPoints Font size (in points)
+ * @return int Font size (in pixels)
+ */
+ public static function fontSizeToPixels($fontSizeInPoints = 11) {
+ return (int) ((4 / 3) * $fontSizeInPoints);
+ }
+
+ /**
+ * Calculate an (approximate) pixel size, based on inch size
+ *
+ * @param int $sizeInInch Font size (in inch)
+ * @return int Size (in pixels)
+ */
+ public static function inchSizeToPixels($sizeInInch = 1) {
+ return ($sizeInInch * 96);
+ }
+
+ /**
+ * Calculate an (approximate) pixel size, based on centimeter size
+ *
+ * @param int $sizeInCm Font size (in centimeters)
+ * @return int Size (in pixels)
+ */
+ public static function centimeterSizeToPixels($sizeInCm = 1) {
+ return ($sizeInCm * 37.795275591);
+ }
+
+ /**
+ * Returns the font path given the font
+ *
+ * @param PHPExcel_Style_Font
+ * @return string Path to TrueType font file
+ */
+ public static function getTrueTypeFontFileFromFont($font) {
+ if (!file_exists(self::$trueTypeFontPath) || !is_dir(self::$trueTypeFontPath)) {
+ throw new PHPExcel_Exception('Valid directory to TrueType Font files not specified');
+ }
+
+ $name = $font->getName();
+ $bold = $font->getBold();
+ $italic = $font->getItalic();
+
+ // Check if we can map font to true type font file
+ switch ($name) {
+ case 'Arial':
+ $fontFile = (
+ $bold ? ($italic ? self::ARIAL_BOLD_ITALIC : self::ARIAL_BOLD)
+ : ($italic ? self::ARIAL_ITALIC : self::ARIAL)
+ );
+ break;
+
+ case 'Calibri':
+ $fontFile = (
+ $bold ? ($italic ? self::CALIBRI_BOLD_ITALIC : self::CALIBRI_BOLD)
+ : ($italic ? self::CALIBRI_ITALIC : self::CALIBRI)
+ );
+ break;
+
+ case 'Courier New':
+ $fontFile = (
+ $bold ? ($italic ? self::COURIER_NEW_BOLD_ITALIC : self::COURIER_NEW_BOLD)
+ : ($italic ? self::COURIER_NEW_ITALIC : self::COURIER_NEW)
+ );
+ break;
+
+ case 'Comic Sans MS':
+ $fontFile = (
+ $bold ? self::COMIC_SANS_MS_BOLD : self::COMIC_SANS_MS
+ );
+ break;
+
+ case 'Georgia':
+ $fontFile = (
+ $bold ? ($italic ? self::GEORGIA_BOLD_ITALIC : self::GEORGIA_BOLD)
+ : ($italic ? self::GEORGIA_ITALIC : self::GEORGIA)
+ );
+ break;
+
+ case 'Impact':
+ $fontFile = self::IMPACT;
+ break;
+
+ case 'Liberation Sans':
+ $fontFile = (
+ $bold ? ($italic ? self::LIBERATION_SANS_BOLD_ITALIC : self::LIBERATION_SANS_BOLD)
+ : ($italic ? self::LIBERATION_SANS_ITALIC : self::LIBERATION_SANS)
+ );
+ break;
+
+ case 'Lucida Console':
+ $fontFile = self::LUCIDA_CONSOLE;
+ break;
+
+ case 'Lucida Sans Unicode':
+ $fontFile = self::LUCIDA_SANS_UNICODE;
+ break;
+
+ case 'Microsoft Sans Serif':
+ $fontFile = self::MICROSOFT_SANS_SERIF;
+ break;
+
+ case 'Palatino Linotype':
+ $fontFile = (
+ $bold ? ($italic ? self::PALATINO_LINOTYPE_BOLD_ITALIC : self::PALATINO_LINOTYPE_BOLD)
+ : ($italic ? self::PALATINO_LINOTYPE_ITALIC : self::PALATINO_LINOTYPE)
+ );
+ break;
+
+ case 'Symbol':
+ $fontFile = self::SYMBOL;
+ break;
+
+ case 'Tahoma':
+ $fontFile = (
+ $bold ? self::TAHOMA_BOLD : self::TAHOMA
+ );
+ break;
+
+ case 'Times New Roman':
+ $fontFile = (
+ $bold ? ($italic ? self::TIMES_NEW_ROMAN_BOLD_ITALIC : self::TIMES_NEW_ROMAN_BOLD)
+ : ($italic ? self::TIMES_NEW_ROMAN_ITALIC : self::TIMES_NEW_ROMAN)
+ );
+ break;
+
+ case 'Trebuchet MS':
+ $fontFile = (
+ $bold ? ($italic ? self::TREBUCHET_MS_BOLD_ITALIC : self::TREBUCHET_MS_BOLD)
+ : ($italic ? self::TREBUCHET_MS_ITALIC : self::TREBUCHET_MS)
+ );
+ break;
+
+ case 'Verdana':
+ $fontFile = (
+ $bold ? ($italic ? self::VERDANA_BOLD_ITALIC : self::VERDANA_BOLD)
+ : ($italic ? self::VERDANA_ITALIC : self::VERDANA)
+ );
+ break;
+
+ default:
+ throw new PHPExcel_Exception('Unknown font name "'. $name .'". Cannot map to TrueType font file');
+ break;
+ }
+
+ $fontFile = self::$trueTypeFontPath . $fontFile;
+
+ // Check if file actually exists
+ if (!file_exists($fontFile)) {
+ throw New PHPExcel_Exception('TrueType Font file not found');
+ }
+
+ return $fontFile;
+ }
+
+ /**
+ * Returns the associated charset for the font name.
+ *
+ * @param string $name Font name
+ * @return int Character set code
+ */
+ public static function getCharsetFromFontName($name)
+ {
+ switch ($name) {
+ // Add more cases. Check FONT records in real Excel files.
+ case 'EucrosiaUPC': return self::CHARSET_ANSI_THAI;
+ case 'Wingdings': return self::CHARSET_SYMBOL;
+ case 'Wingdings 2': return self::CHARSET_SYMBOL;
+ case 'Wingdings 3': return self::CHARSET_SYMBOL;
+ default: return self::CHARSET_ANSI_LATIN;
+ }
+ }
+
+ /**
+ * Get the effective column width for columns without a column dimension or column with width -1
+ * For example, for Calibri 11 this is 9.140625 (64 px)
+ *
+ * @param PHPExcel_Style_Font $font The workbooks default font
+ * @param boolean $pPixels true = return column width in pixels, false = return in OOXML units
+ * @return mixed Column width
+ */
+ public static function getDefaultColumnWidthByFont(PHPExcel_Style_Font $font, $pPixels = false)
+ {
+ if (isset(self::$defaultColumnWidths[$font->getName()][$font->getSize()])) {
+ // Exact width can be determined
+ $columnWidth = $pPixels ?
+ self::$defaultColumnWidths[$font->getName()][$font->getSize()]['px']
+ : self::$defaultColumnWidths[$font->getName()][$font->getSize()]['width'];
+
+ } else {
+ // We don't have data for this particular font and size, use approximation by
+ // extrapolating from Calibri 11
+ $columnWidth = $pPixels ?
+ self::$defaultColumnWidths['Calibri'][11]['px']
+ : self::$defaultColumnWidths['Calibri'][11]['width'];
+ $columnWidth = $columnWidth * $font->getSize() / 11;
+
+ // Round pixels to closest integer
+ if ($pPixels) {
+ $columnWidth = (int) round($columnWidth);
+ }
+ }
+
+ return $columnWidth;
+ }
+
+ /**
+ * Get the effective row height for rows without a row dimension or rows with height -1
+ * For example, for Calibri 11 this is 15 points
+ *
+ * @param PHPExcel_Style_Font $font The workbooks default font
+ * @return float Row height in points
+ */
+ public static function getDefaultRowHeightByFont(PHPExcel_Style_Font $font)
+ {
+ switch ($font->getName()) {
+ case 'Arial':
+ switch ($font->getSize()) {
+ case 10:
+ // inspection of Arial 10 workbook says 12.75pt ~17px
+ $rowHeight = 12.75;
+ break;
+
+ case 9:
+ // inspection of Arial 9 workbook says 12.00pt ~16px
+ $rowHeight = 12;
+ break;
+
+ case 8:
+ // inspection of Arial 8 workbook says 11.25pt ~15px
+ $rowHeight = 11.25;
+ break;
+
+ case 7:
+ // inspection of Arial 7 workbook says 9.00pt ~12px
+ $rowHeight = 9;
+ break;
+
+ case 6:
+ case 5:
+ // inspection of Arial 5,6 workbook says 8.25pt ~11px
+ $rowHeight = 8.25;
+ break;
+
+ case 4:
+ // inspection of Arial 4 workbook says 6.75pt ~9px
+ $rowHeight = 6.75;
+ break;
+
+ case 3:
+ // inspection of Arial 3 workbook says 6.00pt ~8px
+ $rowHeight = 6;
+ break;
+
+ case 2:
+ case 1:
+ // inspection of Arial 1,2 workbook says 5.25pt ~7px
+ $rowHeight = 5.25;
+ break;
+
+ default:
+ // use Arial 10 workbook as an approximation, extrapolation
+ $rowHeight = 12.75 * $font->getSize() / 10;
+ break;
+ }
+ break;
+
+ case 'Calibri':
+ switch ($font->getSize()) {
+ case 11:
+ // inspection of Calibri 11 workbook says 15.00pt ~20px
+ $rowHeight = 15;
+ break;
+
+ case 10:
+ // inspection of Calibri 10 workbook says 12.75pt ~17px
+ $rowHeight = 12.75;
+ break;
+
+ case 9:
+ // inspection of Calibri 9 workbook says 12.00pt ~16px
+ $rowHeight = 12;
+ break;
+
+ case 8:
+ // inspection of Calibri 8 workbook says 11.25pt ~15px
+ $rowHeight = 11.25;
+ break;
+
+ case 7:
+ // inspection of Calibri 7 workbook says 9.00pt ~12px
+ $rowHeight = 9;
+ break;
+
+ case 6:
+ case 5:
+ // inspection of Calibri 5,6 workbook says 8.25pt ~11px
+ $rowHeight = 8.25;
+ break;
+
+ case 4:
+ // inspection of Calibri 4 workbook says 6.75pt ~9px
+ $rowHeight = 6.75;
+ break;
+
+ case 3:
+ // inspection of Calibri 3 workbook says 6.00pt ~8px
+ $rowHeight = 6.00;
+ break;
+
+ case 2:
+ case 1:
+ // inspection of Calibri 1,2 workbook says 5.25pt ~7px
+ $rowHeight = 5.25;
+ break;
+
+ default:
+ // use Calibri 11 workbook as an approximation, extrapolation
+ $rowHeight = 15 * $font->getSize() / 11;
+ break;
+ }
+ break;
+
+ case 'Verdana':
+ switch ($font->getSize()) {
+ case 10:
+ // inspection of Verdana 10 workbook says 12.75pt ~17px
+ $rowHeight = 12.75;
+ break;
+
+ case 9:
+ // inspection of Verdana 9 workbook says 11.25pt ~15px
+ $rowHeight = 11.25;
+ break;
+
+ case 8:
+ // inspection of Verdana 8 workbook says 10.50pt ~14px
+ $rowHeight = 10.50;
+ break;
+
+ case 7:
+ // inspection of Verdana 7 workbook says 9.00pt ~12px
+ $rowHeight = 9.00;
+ break;
+
+ case 6:
+ case 5:
+ // inspection of Verdana 5,6 workbook says 8.25pt ~11px
+ $rowHeight = 8.25;
+ break;
+
+ case 4:
+ // inspection of Verdana 4 workbook says 6.75pt ~9px
+ $rowHeight = 6.75;
+ break;
+
+ case 3:
+ // inspection of Verdana 3 workbook says 6.00pt ~8px
+ $rowHeight = 6;
+ break;
+
+ case 2:
+ case 1:
+ // inspection of Verdana 1,2 workbook says 5.25pt ~7px
+ $rowHeight = 5.25;
+ break;
+
+ default:
+ // use Verdana 10 workbook as an approximation, extrapolation
+ $rowHeight = 12.75 * $font->getSize() / 10;
+ break;
+ }
+ break;
+
+ default:
+ // just use Calibri as an approximation
+ $rowHeight = 15 * $font->getSize() / 11;
+ break;
+ }
+
+ return $rowHeight;
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/OLE.php b/includes/PHPExcel/Classes/PHPExcel/Shared/OLE.php
new file mode 100644
index 0000000..9796282
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/OLE.php
@@ -0,0 +1,531 @@
+ |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+// $Id: OLE.php,v 1.13 2007/03/07 14:38:25 schmidt Exp $
+
+
+/**
+* Array for storing OLE instances that are accessed from
+* OLE_ChainedBlockStream::stream_open().
+* @var array
+*/
+$GLOBALS['_OLE_INSTANCES'] = array();
+
+/**
+* OLE package base class.
+*
+* @author Xavier Noguer
+* @author Christian Schmidt
+* @category PHPExcel
+* @package PHPExcel_Shared_OLE
+*/
+class PHPExcel_Shared_OLE
+{
+ const OLE_PPS_TYPE_ROOT = 5;
+ const OLE_PPS_TYPE_DIR = 1;
+ const OLE_PPS_TYPE_FILE = 2;
+ const OLE_DATA_SIZE_SMALL = 0x1000;
+ const OLE_LONG_INT_SIZE = 4;
+ const OLE_PPS_SIZE = 0x80;
+
+ /**
+ * The file handle for reading an OLE container
+ * @var resource
+ */
+ public $_file_handle;
+
+ /**
+ * Array of PPS's found on the OLE container
+ * @var array
+ */
+ public $_list = array();
+
+ /**
+ * Root directory of OLE container
+ * @var OLE_PPS_Root
+ */
+ public $root;
+
+ /**
+ * Big Block Allocation Table
+ * @var array (blockId => nextBlockId)
+ */
+ public $bbat;
+
+ /**
+ * Short Block Allocation Table
+ * @var array (blockId => nextBlockId)
+ */
+ public $sbat;
+
+ /**
+ * Size of big blocks. This is usually 512.
+ * @var int number of octets per block.
+ */
+ public $bigBlockSize;
+
+ /**
+ * Size of small blocks. This is usually 64.
+ * @var int number of octets per block
+ */
+ public $smallBlockSize;
+
+ /**
+ * Reads an OLE container from the contents of the file given.
+ *
+ * @acces public
+ * @param string $file
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ public function read($file)
+ {
+ $fh = fopen($file, "r");
+ if (!$fh) {
+ throw new PHPExcel_Reader_Exception("Can't open file $file");
+ }
+ $this->_file_handle = $fh;
+
+ $signature = fread($fh, 8);
+ if ("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" != $signature) {
+ throw new PHPExcel_Reader_Exception("File doesn't seem to be an OLE container.");
+ }
+ fseek($fh, 28);
+ if (fread($fh, 2) != "\xFE\xFF") {
+ // This shouldn't be a problem in practice
+ throw new PHPExcel_Reader_Exception("Only Little-Endian encoding is supported.");
+ }
+ // Size of blocks and short blocks in bytes
+ $this->bigBlockSize = pow(2, self::_readInt2($fh));
+ $this->smallBlockSize = pow(2, self::_readInt2($fh));
+
+ // Skip UID, revision number and version number
+ fseek($fh, 44);
+ // Number of blocks in Big Block Allocation Table
+ $bbatBlockCount = self::_readInt4($fh);
+
+ // Root chain 1st block
+ $directoryFirstBlockId = self::_readInt4($fh);
+
+ // Skip unused bytes
+ fseek($fh, 56);
+ // Streams shorter than this are stored using small blocks
+ $this->bigBlockThreshold = self::_readInt4($fh);
+ // Block id of first sector in Short Block Allocation Table
+ $sbatFirstBlockId = self::_readInt4($fh);
+ // Number of blocks in Short Block Allocation Table
+ $sbbatBlockCount = self::_readInt4($fh);
+ // Block id of first sector in Master Block Allocation Table
+ $mbatFirstBlockId = self::_readInt4($fh);
+ // Number of blocks in Master Block Allocation Table
+ $mbbatBlockCount = self::_readInt4($fh);
+ $this->bbat = array();
+
+ // Remaining 4 * 109 bytes of current block is beginning of Master
+ // Block Allocation Table
+ $mbatBlocks = array();
+ for ($i = 0; $i < 109; ++$i) {
+ $mbatBlocks[] = self::_readInt4($fh);
+ }
+
+ // Read rest of Master Block Allocation Table (if any is left)
+ $pos = $this->_getBlockOffset($mbatFirstBlockId);
+ for ($i = 0; $i < $mbbatBlockCount; ++$i) {
+ fseek($fh, $pos);
+ for ($j = 0; $j < $this->bigBlockSize / 4 - 1; ++$j) {
+ $mbatBlocks[] = self::_readInt4($fh);
+ }
+ // Last block id in each block points to next block
+ $pos = $this->_getBlockOffset(self::_readInt4($fh));
+ }
+
+ // Read Big Block Allocation Table according to chain specified by
+ // $mbatBlocks
+ for ($i = 0; $i < $bbatBlockCount; ++$i) {
+ $pos = $this->_getBlockOffset($mbatBlocks[$i]);
+ fseek($fh, $pos);
+ for ($j = 0 ; $j < $this->bigBlockSize / 4; ++$j) {
+ $this->bbat[] = self::_readInt4($fh);
+ }
+ }
+
+ // Read short block allocation table (SBAT)
+ $this->sbat = array();
+ $shortBlockCount = $sbbatBlockCount * $this->bigBlockSize / 4;
+ $sbatFh = $this->getStream($sbatFirstBlockId);
+ for ($blockId = 0; $blockId < $shortBlockCount; ++$blockId) {
+ $this->sbat[$blockId] = self::_readInt4($sbatFh);
+ }
+ fclose($sbatFh);
+
+ $this->_readPpsWks($directoryFirstBlockId);
+
+ return true;
+ }
+
+ /**
+ * @param int block id
+ * @param int byte offset from beginning of file
+ * @access public
+ */
+ public function _getBlockOffset($blockId)
+ {
+ return 512 + $blockId * $this->bigBlockSize;
+ }
+
+ /**
+ * Returns a stream for use with fread() etc. External callers should
+ * use PHPExcel_Shared_OLE_PPS_File::getStream().
+ * @param int|PPS block id or PPS
+ * @return resource read-only stream
+ */
+ public function getStream($blockIdOrPps)
+ {
+ static $isRegistered = false;
+ if (!$isRegistered) {
+ stream_wrapper_register('ole-chainedblockstream',
+ 'PHPExcel_Shared_OLE_ChainedBlockStream');
+ $isRegistered = true;
+ }
+
+ // Store current instance in global array, so that it can be accessed
+ // in OLE_ChainedBlockStream::stream_open().
+ // Object is removed from self::$instances in OLE_Stream::close().
+ $GLOBALS['_OLE_INSTANCES'][] = $this;
+ $instanceId = end(array_keys($GLOBALS['_OLE_INSTANCES']));
+
+ $path = 'ole-chainedblockstream://oleInstanceId=' . $instanceId;
+ if ($blockIdOrPps instanceof PHPExcel_Shared_OLE_PPS) {
+ $path .= '&blockId=' . $blockIdOrPps->_StartBlock;
+ $path .= '&size=' . $blockIdOrPps->Size;
+ } else {
+ $path .= '&blockId=' . $blockIdOrPps;
+ }
+ return fopen($path, 'r');
+ }
+
+ /**
+ * Reads a signed char.
+ * @param resource file handle
+ * @return int
+ * @access public
+ */
+ private static function _readInt1($fh)
+ {
+ list(, $tmp) = unpack("c", fread($fh, 1));
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned short (2 octets).
+ * @param resource file handle
+ * @return int
+ * @access public
+ */
+ private static function _readInt2($fh)
+ {
+ list(, $tmp) = unpack("v", fread($fh, 2));
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned long (4 octets).
+ * @param resource file handle
+ * @return int
+ * @access public
+ */
+ private static function _readInt4($fh)
+ {
+ list(, $tmp) = unpack("V", fread($fh, 4));
+ return $tmp;
+ }
+
+ /**
+ * Gets information about all PPS's on the OLE container from the PPS WK's
+ * creates an OLE_PPS object for each one.
+ *
+ * @access public
+ * @param integer the block id of the first block
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ public function _readPpsWks($blockId)
+ {
+ $fh = $this->getStream($blockId);
+ for ($pos = 0; ; $pos += 128) {
+ fseek($fh, $pos, SEEK_SET);
+ $nameUtf16 = fread($fh, 64);
+ $nameLength = self::_readInt2($fh);
+ $nameUtf16 = substr($nameUtf16, 0, $nameLength - 2);
+ // Simple conversion from UTF-16LE to ISO-8859-1
+ $name = str_replace("\x00", "", $nameUtf16);
+ $type = self::_readInt1($fh);
+ switch ($type) {
+ case self::OLE_PPS_TYPE_ROOT:
+ $pps = new PHPExcel_Shared_OLE_PPS_Root(null, null, array());
+ $this->root = $pps;
+ break;
+ case self::OLE_PPS_TYPE_DIR:
+ $pps = new PHPExcel_Shared_OLE_PPS(null, null, null, null, null,
+ null, null, null, null, array());
+ break;
+ case self::OLE_PPS_TYPE_FILE:
+ $pps = new PHPExcel_Shared_OLE_PPS_File($name);
+ break;
+ default:
+ continue;
+ }
+ fseek($fh, 1, SEEK_CUR);
+ $pps->Type = $type;
+ $pps->Name = $name;
+ $pps->PrevPps = self::_readInt4($fh);
+ $pps->NextPps = self::_readInt4($fh);
+ $pps->DirPps = self::_readInt4($fh);
+ fseek($fh, 20, SEEK_CUR);
+ $pps->Time1st = self::OLE2LocalDate(fread($fh, 8));
+ $pps->Time2nd = self::OLE2LocalDate(fread($fh, 8));
+ $pps->_StartBlock = self::_readInt4($fh);
+ $pps->Size = self::_readInt4($fh);
+ $pps->No = count($this->_list);
+ $this->_list[] = $pps;
+
+ // check if the PPS tree (starting from root) is complete
+ if (isset($this->root) &&
+ $this->_ppsTreeComplete($this->root->No)) {
+
+ break;
+ }
+ }
+ fclose($fh);
+
+ // Initialize $pps->children on directories
+ foreach ($this->_list as $pps) {
+ if ($pps->Type == self::OLE_PPS_TYPE_DIR || $pps->Type == self::OLE_PPS_TYPE_ROOT) {
+ $nos = array($pps->DirPps);
+ $pps->children = array();
+ while ($nos) {
+ $no = array_pop($nos);
+ if ($no != -1) {
+ $childPps = $this->_list[$no];
+ $nos[] = $childPps->PrevPps;
+ $nos[] = $childPps->NextPps;
+ $pps->children[] = $childPps;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * It checks whether the PPS tree is complete (all PPS's read)
+ * starting with the given PPS (not necessarily root)
+ *
+ * @access public
+ * @param integer $index The index of the PPS from which we are checking
+ * @return boolean Whether the PPS tree for the given PPS is complete
+ */
+ public function _ppsTreeComplete($index)
+ {
+ return isset($this->_list[$index]) &&
+ ($pps = $this->_list[$index]) &&
+ ($pps->PrevPps == -1 ||
+ $this->_ppsTreeComplete($pps->PrevPps)) &&
+ ($pps->NextPps == -1 ||
+ $this->_ppsTreeComplete($pps->NextPps)) &&
+ ($pps->DirPps == -1 ||
+ $this->_ppsTreeComplete($pps->DirPps));
+ }
+
+ /**
+ * Checks whether a PPS is a File PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ *
+ * @access public
+ * @param integer $index The index for the PPS
+ * @return bool true if it's a File PPS, false otherwise
+ */
+ public function isFile($index)
+ {
+ if (isset($this->_list[$index])) {
+ return ($this->_list[$index]->Type == self::OLE_PPS_TYPE_FILE);
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a PPS is a Root PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ *
+ * @access public
+ * @param integer $index The index for the PPS.
+ * @return bool true if it's a Root PPS, false otherwise
+ */
+ public function isRoot($index)
+ {
+ if (isset($this->_list[$index])) {
+ return ($this->_list[$index]->Type == self::OLE_PPS_TYPE_ROOT);
+ }
+ return false;
+ }
+
+ /**
+ * Gives the total number of PPS's found in the OLE container.
+ *
+ * @access public
+ * @return integer The total number of PPS's found in the OLE container
+ */
+ public function ppsTotal()
+ {
+ return count($this->_list);
+ }
+
+ /**
+ * Gets data from a PPS
+ * If there is no PPS for the index given, it will return an empty string.
+ *
+ * @access public
+ * @param integer $index The index for the PPS
+ * @param integer $position The position from which to start reading
+ * (relative to the PPS)
+ * @param integer $length The amount of bytes to read (at most)
+ * @return string The binary string containing the data requested
+ * @see OLE_PPS_File::getStream()
+ */
+ public function getData($index, $position, $length)
+ {
+ // if position is not valid return empty string
+ if (!isset($this->_list[$index]) || ($position >= $this->_list[$index]->Size) || ($position < 0)) {
+ return '';
+ }
+ $fh = $this->getStream($this->_list[$index]);
+ $data = stream_get_contents($fh, $length, $position);
+ fclose($fh);
+ return $data;
+ }
+
+ /**
+ * Gets the data length from a PPS
+ * If there is no PPS for the index given, it will return 0.
+ *
+ * @access public
+ * @param integer $index The index for the PPS
+ * @return integer The amount of bytes in data the PPS has
+ */
+ public function getDataLength($index)
+ {
+ if (isset($this->_list[$index])) {
+ return $this->_list[$index]->Size;
+ }
+ return 0;
+ }
+
+ /**
+ * Utility function to transform ASCII text to Unicode
+ *
+ * @access public
+ * @static
+ * @param string $ascii The ASCII string to transform
+ * @return string The string in Unicode
+ */
+ public static function Asc2Ucs($ascii)
+ {
+ $rawname = '';
+ for ($i = 0; $i < strlen($ascii); ++$i) {
+ $rawname .= $ascii{$i} . "\x00";
+ }
+ return $rawname;
+ }
+
+ /**
+ * Utility function
+ * Returns a string for the OLE container with the date given
+ *
+ * @access public
+ * @static
+ * @param integer $date A timestamp
+ * @return string The string for the OLE container
+ */
+ public static function LocalDate2OLE($date = null)
+ {
+ if (!isset($date)) {
+ return "\x00\x00\x00\x00\x00\x00\x00\x00";
+ }
+
+ // factor used for separating numbers into 4 bytes parts
+ $factor = pow(2, 32);
+
+ // days from 1-1-1601 until the beggining of UNIX era
+ $days = 134774;
+ // calculate seconds
+ $big_date = $days*24*3600 + gmmktime(date("H",$date),date("i",$date),date("s",$date),
+ date("m",$date),date("d",$date),date("Y",$date));
+ // multiply just to make MS happy
+ $big_date *= 10000000;
+
+ $high_part = floor($big_date / $factor);
+ // lower 4 bytes
+ $low_part = floor((($big_date / $factor) - $high_part) * $factor);
+
+ // Make HEX string
+ $res = '';
+
+ for ($i = 0; $i < 4; ++$i) {
+ $hex = $low_part % 0x100;
+ $res .= pack('c', $hex);
+ $low_part /= 0x100;
+ }
+ for ($i = 0; $i < 4; ++$i) {
+ $hex = $high_part % 0x100;
+ $res .= pack('c', $hex);
+ $high_part /= 0x100;
+ }
+ return $res;
+ }
+
+ /**
+ * Returns a timestamp from an OLE container's date
+ *
+ * @access public
+ * @static
+ * @param integer $string A binary string with the encoded date
+ * @return string The timestamp corresponding to the string
+ */
+ public static function OLE2LocalDate($string)
+ {
+ if (strlen($string) != 8) {
+ return new PEAR_Error("Expecting 8 byte string");
+ }
+
+ // factor used for separating numbers into 4 bytes parts
+ $factor = pow(2,32);
+ list(, $high_part) = unpack('V', substr($string, 4, 4));
+ list(, $low_part) = unpack('V', substr($string, 0, 4));
+
+ $big_date = ($high_part * $factor) + $low_part;
+ // translate to seconds
+ $big_date /= 10000000;
+
+ // days from 1-1-1601 until the beggining of UNIX era
+ $days = 134774;
+
+ // translate to seconds from beggining of UNIX era
+ $big_date -= $days * 24 * 3600;
+ return floor($big_date);
+ }
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/OLERead.php b/includes/PHPExcel/Classes/PHPExcel/Shared/OLERead.php
new file mode 100644
index 0000000..261bdde
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/OLERead.php
@@ -0,0 +1,317 @@
+data = file_get_contents($sFileName, FALSE, NULL, 0, 8);
+
+ // Check OLE identifier
+ if ($this->data != self::IDENTIFIER_OLE) {
+ throw new PHPExcel_Reader_Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
+ }
+
+ // Get the file data
+ $this->data = file_get_contents($sFileName);
+
+ // Total number of sectors used for the SAT
+ $this->numBigBlockDepotBlocks = self::_GetInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
+
+ // SecID of the first sector of the directory stream
+ $this->rootStartBlock = self::_GetInt4d($this->data, self::ROOT_START_BLOCK_POS);
+
+ // SecID of the first sector of the SSAT (or -2 if not extant)
+ $this->sbdStartBlock = self::_GetInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
+
+ // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
+ $this->extensionBlock = self::_GetInt4d($this->data, self::EXTENSION_BLOCK_POS);
+
+ // Total number of sectors used by MSAT
+ $this->numExtensionBlocks = self::_GetInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
+
+ $bigBlockDepotBlocks = array();
+ $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
+
+ $bbdBlocks = $this->numBigBlockDepotBlocks;
+
+ if ($this->numExtensionBlocks != 0) {
+ $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
+ }
+
+ for ($i = 0; $i < $bbdBlocks; ++$i) {
+ $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
+ $pos += 4;
+ }
+
+ for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
+ $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
+ $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
+
+ for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
+ $bigBlockDepotBlocks[$i] = self::_GetInt4d($this->data, $pos);
+ $pos += 4;
+ }
+
+ $bbdBlocks += $blocksToRead;
+ if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
+ $this->extensionBlock = self::_GetInt4d($this->data, $pos);
+ }
+ }
+
+ $pos = 0;
+ $this->bigBlockChain = '';
+ $bbs = self::BIG_BLOCK_SIZE / 4;
+ for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
+ $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
+
+ $this->bigBlockChain .= substr($this->data, $pos, 4*$bbs);
+ $pos += 4*$bbs;
+ }
+
+ $pos = 0;
+ $sbdBlock = $this->sbdStartBlock;
+ $this->smallBlockChain = '';
+ while ($sbdBlock != -2) {
+ $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
+
+ $this->smallBlockChain .= substr($this->data, $pos, 4*$bbs);
+ $pos += 4*$bbs;
+
+ $sbdBlock = self::_GetInt4d($this->bigBlockChain, $sbdBlock*4);
+ }
+
+ // read the directory stream
+ $block = $this->rootStartBlock;
+ $this->entry = $this->_readData($block);
+
+ $this->_readPropertySets();
+ }
+
+ /**
+ * Extract binary stream data
+ *
+ * @return string
+ */
+ public function getStream($stream)
+ {
+ if ($stream === NULL) {
+ return null;
+ }
+
+ $streamData = '';
+
+ if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {
+ $rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']);
+
+ $block = $this->props[$stream]['startBlock'];
+
+ while ($block != -2) {
+ $pos = $block * self::SMALL_BLOCK_SIZE;
+ $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
+
+ $block = self::_GetInt4d($this->smallBlockChain, $block*4);
+ }
+
+ return $streamData;
+ } else {
+ $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;
+ if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {
+ ++$numBlocks;
+ }
+
+ if ($numBlocks == 0) return '';
+
+ $block = $this->props[$stream]['startBlock'];
+
+ while ($block != -2) {
+ $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
+ $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
+ $block = self::_GetInt4d($this->bigBlockChain, $block*4);
+ }
+
+ return $streamData;
+ }
+ }
+
+ /**
+ * Read a standard stream (by joining sectors using information from SAT)
+ *
+ * @param int $bl Sector ID where the stream starts
+ * @return string Data for standard stream
+ */
+ private function _readData($bl)
+ {
+ $block = $bl;
+ $data = '';
+
+ while ($block != -2) {
+ $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
+ $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
+ $block = self::_GetInt4d($this->bigBlockChain, $block*4);
+ }
+ return $data;
+ }
+
+ /**
+ * Read entries in the directory stream.
+ */
+ private function _readPropertySets() {
+ $offset = 0;
+
+ // loop through entires, each entry is 128 bytes
+ $entryLen = strlen($this->entry);
+ while ($offset < $entryLen) {
+ // entry data (128 bytes)
+ $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
+
+ // size in bytes of name
+ $nameSize = ord($d[self::SIZE_OF_NAME_POS]) | (ord($d[self::SIZE_OF_NAME_POS+1]) << 8);
+
+ // type of entry
+ $type = ord($d[self::TYPE_POS]);
+
+ // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)
+ // sectorID of first sector of the short-stream container stream, if this entry is root entry
+ $startBlock = self::_GetInt4d($d, self::START_BLOCK_POS);
+
+ $size = self::_GetInt4d($d, self::SIZE_POS);
+
+ $name = str_replace("\x00", "", substr($d,0,$nameSize));
+
+
+ $this->props[] = array (
+ 'name' => $name,
+ 'type' => $type,
+ 'startBlock' => $startBlock,
+ 'size' => $size);
+
+ // tmp helper to simplify checks
+ $upName = strtoupper($name);
+
+ // Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)
+ if (($upName === 'WORKBOOK') || ($upName === 'BOOK')) {
+ $this->wrkbook = count($this->props) - 1;
+ }
+ else if ( $upName === 'ROOT ENTRY' || $upName === 'R') {
+ // Root entry
+ $this->rootentry = count($this->props) - 1;
+ }
+
+ // Summary information
+ if ($name == chr(5) . 'SummaryInformation') {
+// echo 'Summary Information
';
+ $this->summaryInformation = count($this->props) - 1;
+ }
+
+ // Additional Document Summary information
+ if ($name == chr(5) . 'DocumentSummaryInformation') {
+// echo 'Document Summary Information
';
+ $this->documentSummaryInformation = count($this->props) - 1;
+ }
+
+ $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
+ }
+
+ }
+
+ /**
+ * Read 4 bytes of data at specified position
+ *
+ * @param string $data
+ * @param int $pos
+ * @return int
+ */
+ private static function _GetInt4d($data, $pos)
+ {
+ // FIX: represent numbers correctly on 64-bit system
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
+ // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
+ $_or_24 = ord($data[$pos + 3]);
+ if ($_or_24 >= 128) {
+ // negative number
+ $_ord_24 = -abs((256 - $_or_24) << 24);
+ } else {
+ $_ord_24 = ($_or_24 & 127) << 24;
+ }
+ return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24;
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/PasswordHasher.php b/includes/PHPExcel/Classes/PHPExcel/Shared/PasswordHasher.php
new file mode 100644
index 0000000..891b6bc
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/PasswordHasher.php
@@ -0,0 +1,66 @@
+.
+ *
+ * @param string $pPassword Password to hash
+ * @return string Hashed password
+ */
+ public static function hashPassword($pPassword = '') {
+ $password = 0x0000;
+ $charPos = 1; // char position
+
+ // split the plain text password in its component characters
+ $chars = preg_split('//', $pPassword, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ($chars as $char) {
+ $value = ord($char) << $charPos++; // shifted ASCII value
+ $rotated_bits = $value >> 15; // rotated bits beyond bit 15
+ $value &= 0x7fff; // first 15 bits
+ $password ^= ($value | $rotated_bits);
+ }
+
+ $password ^= strlen($pPassword);
+ $password ^= 0xCE4B;
+
+ return(strtoupper(dechex($password)));
+ }
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/String.php b/includes/PHPExcel/Classes/PHPExcel/Shared/String.php
new file mode 100644
index 0000000..7d6b419
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/String.php
@@ -0,0 +1,811 @@
+ chr(0),
+ "\x1B 1" => chr(1),
+ "\x1B 2" => chr(2),
+ "\x1B 3" => chr(3),
+ "\x1B 4" => chr(4),
+ "\x1B 5" => chr(5),
+ "\x1B 6" => chr(6),
+ "\x1B 7" => chr(7),
+ "\x1B 8" => chr(8),
+ "\x1B 9" => chr(9),
+ "\x1B :" => chr(10),
+ "\x1B ;" => chr(11),
+ "\x1B <" => chr(12),
+ "\x1B :" => chr(13),
+ "\x1B >" => chr(14),
+ "\x1B ?" => chr(15),
+ "\x1B!0" => chr(16),
+ "\x1B!1" => chr(17),
+ "\x1B!2" => chr(18),
+ "\x1B!3" => chr(19),
+ "\x1B!4" => chr(20),
+ "\x1B!5" => chr(21),
+ "\x1B!6" => chr(22),
+ "\x1B!7" => chr(23),
+ "\x1B!8" => chr(24),
+ "\x1B!9" => chr(25),
+ "\x1B!:" => chr(26),
+ "\x1B!;" => chr(27),
+ "\x1B!<" => chr(28),
+ "\x1B!=" => chr(29),
+ "\x1B!>" => chr(30),
+ "\x1B!?" => chr(31),
+ "\x1B'?" => chr(127),
+ "\x1B(0" => '€', // 128 in CP1252
+ "\x1B(2" => '‚', // 130 in CP1252
+ "\x1B(3" => 'ƒ', // 131 in CP1252
+ "\x1B(4" => '„', // 132 in CP1252
+ "\x1B(5" => '…', // 133 in CP1252
+ "\x1B(6" => '†', // 134 in CP1252
+ "\x1B(7" => '‡', // 135 in CP1252
+ "\x1B(8" => 'ˆ', // 136 in CP1252
+ "\x1B(9" => '‰', // 137 in CP1252
+ "\x1B(:" => 'Š', // 138 in CP1252
+ "\x1B(;" => '‹', // 139 in CP1252
+ "\x1BNj" => 'Œ', // 140 in CP1252
+ "\x1B(>" => 'Ž', // 142 in CP1252
+ "\x1B)1" => '‘', // 145 in CP1252
+ "\x1B)2" => '’', // 146 in CP1252
+ "\x1B)3" => '“', // 147 in CP1252
+ "\x1B)4" => '”', // 148 in CP1252
+ "\x1B)5" => '•', // 149 in CP1252
+ "\x1B)6" => '–', // 150 in CP1252
+ "\x1B)7" => '—', // 151 in CP1252
+ "\x1B)8" => '˜', // 152 in CP1252
+ "\x1B)9" => '™', // 153 in CP1252
+ "\x1B):" => 'š', // 154 in CP1252
+ "\x1B);" => '›', // 155 in CP1252
+ "\x1BNz" => 'œ', // 156 in CP1252
+ "\x1B)>" => 'ž', // 158 in CP1252
+ "\x1B)?" => 'Ÿ', // 159 in CP1252
+ "\x1B*0" => ' ', // 160 in CP1252
+ "\x1BN!" => '¡', // 161 in CP1252
+ "\x1BN\"" => '¢', // 162 in CP1252
+ "\x1BN#" => '£', // 163 in CP1252
+ "\x1BN(" => '¤', // 164 in CP1252
+ "\x1BN%" => '¥', // 165 in CP1252
+ "\x1B*6" => '¦', // 166 in CP1252
+ "\x1BN'" => '§', // 167 in CP1252
+ "\x1BNH " => '¨', // 168 in CP1252
+ "\x1BNS" => '©', // 169 in CP1252
+ "\x1BNc" => 'ª', // 170 in CP1252
+ "\x1BN+" => '«', // 171 in CP1252
+ "\x1B*<" => '¬', // 172 in CP1252
+ "\x1B*=" => '', // 173 in CP1252
+ "\x1BNR" => '®', // 174 in CP1252
+ "\x1B*?" => '¯', // 175 in CP1252
+ "\x1BN0" => '°', // 176 in CP1252
+ "\x1BN1" => '±', // 177 in CP1252
+ "\x1BN2" => '²', // 178 in CP1252
+ "\x1BN3" => '³', // 179 in CP1252
+ "\x1BNB " => '´', // 180 in CP1252
+ "\x1BN5" => 'µ', // 181 in CP1252
+ "\x1BN6" => '¶', // 182 in CP1252
+ "\x1BN7" => '·', // 183 in CP1252
+ "\x1B+8" => '¸', // 184 in CP1252
+ "\x1BNQ" => '¹', // 185 in CP1252
+ "\x1BNk" => 'º', // 186 in CP1252
+ "\x1BN;" => '»', // 187 in CP1252
+ "\x1BN<" => '¼', // 188 in CP1252
+ "\x1BN=" => '½', // 189 in CP1252
+ "\x1BN>" => '¾', // 190 in CP1252
+ "\x1BN?" => '¿', // 191 in CP1252
+ "\x1BNAA" => 'À', // 192 in CP1252
+ "\x1BNBA" => 'Á', // 193 in CP1252
+ "\x1BNCA" => 'Â', // 194 in CP1252
+ "\x1BNDA" => 'Ã', // 195 in CP1252
+ "\x1BNHA" => 'Ä', // 196 in CP1252
+ "\x1BNJA" => 'Å', // 197 in CP1252
+ "\x1BNa" => 'Æ', // 198 in CP1252
+ "\x1BNKC" => 'Ç', // 199 in CP1252
+ "\x1BNAE" => 'È', // 200 in CP1252
+ "\x1BNBE" => 'É', // 201 in CP1252
+ "\x1BNCE" => 'Ê', // 202 in CP1252
+ "\x1BNHE" => 'Ë', // 203 in CP1252
+ "\x1BNAI" => 'Ì', // 204 in CP1252
+ "\x1BNBI" => 'Í', // 205 in CP1252
+ "\x1BNCI" => 'Î', // 206 in CP1252
+ "\x1BNHI" => 'Ï', // 207 in CP1252
+ "\x1BNb" => 'Ð', // 208 in CP1252
+ "\x1BNDN" => 'Ñ', // 209 in CP1252
+ "\x1BNAO" => 'Ò', // 210 in CP1252
+ "\x1BNBO" => 'Ó', // 211 in CP1252
+ "\x1BNCO" => 'Ô', // 212 in CP1252
+ "\x1BNDO" => 'Õ', // 213 in CP1252
+ "\x1BNHO" => 'Ö', // 214 in CP1252
+ "\x1B-7" => '×', // 215 in CP1252
+ "\x1BNi" => 'Ø', // 216 in CP1252
+ "\x1BNAU" => 'Ù', // 217 in CP1252
+ "\x1BNBU" => 'Ú', // 218 in CP1252
+ "\x1BNCU" => 'Û', // 219 in CP1252
+ "\x1BNHU" => 'Ü', // 220 in CP1252
+ "\x1B-=" => 'Ý', // 221 in CP1252
+ "\x1BNl" => 'Þ', // 222 in CP1252
+ "\x1BN{" => 'ß', // 223 in CP1252
+ "\x1BNAa" => 'à', // 224 in CP1252
+ "\x1BNBa" => 'á', // 225 in CP1252
+ "\x1BNCa" => 'â', // 226 in CP1252
+ "\x1BNDa" => 'ã', // 227 in CP1252
+ "\x1BNHa" => 'ä', // 228 in CP1252
+ "\x1BNJa" => 'å', // 229 in CP1252
+ "\x1BNq" => 'æ', // 230 in CP1252
+ "\x1BNKc" => 'ç', // 231 in CP1252
+ "\x1BNAe" => 'è', // 232 in CP1252
+ "\x1BNBe" => 'é', // 233 in CP1252
+ "\x1BNCe" => 'ê', // 234 in CP1252
+ "\x1BNHe" => 'ë', // 235 in CP1252
+ "\x1BNAi" => 'ì', // 236 in CP1252
+ "\x1BNBi" => 'í', // 237 in CP1252
+ "\x1BNCi" => 'î', // 238 in CP1252
+ "\x1BNHi" => 'ï', // 239 in CP1252
+ "\x1BNs" => 'ð', // 240 in CP1252
+ "\x1BNDn" => 'ñ', // 241 in CP1252
+ "\x1BNAo" => 'ò', // 242 in CP1252
+ "\x1BNBo" => 'ó', // 243 in CP1252
+ "\x1BNCo" => 'ô', // 244 in CP1252
+ "\x1BNDo" => 'õ', // 245 in CP1252
+ "\x1BNHo" => 'ö', // 246 in CP1252
+ "\x1B/7" => '÷', // 247 in CP1252
+ "\x1BNy" => 'ø', // 248 in CP1252
+ "\x1BNAu" => 'ù', // 249 in CP1252
+ "\x1BNBu" => 'ú', // 250 in CP1252
+ "\x1BNCu" => 'û', // 251 in CP1252
+ "\x1BNHu" => 'ü', // 252 in CP1252
+ "\x1B/=" => 'ý', // 253 in CP1252
+ "\x1BN|" => 'þ', // 254 in CP1252
+ "\x1BNHy" => 'ÿ', // 255 in CP1252
+ );
+ }
+
+ /**
+ * Get whether mbstring extension is available
+ *
+ * @return boolean
+ */
+ public static function getIsMbstringEnabled()
+ {
+ if (isset(self::$_isMbstringEnabled)) {
+ return self::$_isMbstringEnabled;
+ }
+
+ self::$_isMbstringEnabled = function_exists('mb_convert_encoding') ?
+ true : false;
+
+ return self::$_isMbstringEnabled;
+ }
+
+ /**
+ * Get whether iconv extension is available
+ *
+ * @return boolean
+ */
+ public static function getIsIconvEnabled()
+ {
+ if (isset(self::$_isIconvEnabled)) {
+ return self::$_isIconvEnabled;
+ }
+
+ // Fail if iconv doesn't exist
+ if (!function_exists('iconv')) {
+ self::$_isIconvEnabled = false;
+ return false;
+ }
+
+ // Sometimes iconv is not working, and e.g. iconv('UTF-8', 'UTF-16LE', 'x') just returns false,
+ if (!@iconv('UTF-8', 'UTF-16LE', 'x')) {
+ self::$_isIconvEnabled = false;
+ return false;
+ }
+
+ // Sometimes iconv_substr('A', 0, 1, 'UTF-8') just returns false in PHP 5.2.0
+ // we cannot use iconv in that case either (http://bugs.php.net/bug.php?id=37773)
+ if (!@iconv_substr('A', 0, 1, 'UTF-8')) {
+ self::$_isIconvEnabled = false;
+ return false;
+ }
+
+ // CUSTOM: IBM AIX iconv() does not work
+ if ( defined('PHP_OS') && @stristr(PHP_OS, 'AIX')
+ && defined('ICONV_IMPL') && (@strcasecmp(ICONV_IMPL, 'unknown') == 0)
+ && defined('ICONV_VERSION') && (@strcasecmp(ICONV_VERSION, 'unknown') == 0) )
+ {
+ self::$_isIconvEnabled = false;
+ return false;
+ }
+
+ // If we reach here no problems were detected with iconv
+ self::$_isIconvEnabled = true;
+ return true;
+ }
+
+ public static function buildCharacterSets() {
+ if(empty(self::$_controlCharacters)) {
+ self::_buildControlCharacters();
+ }
+ if(empty(self::$_SYLKCharacters)) {
+ self::_buildSYLKCharacters();
+ }
+ }
+
+ /**
+ * Convert from OpenXML escaped control character to PHP control character
+ *
+ * Excel 2007 team:
+ * ----------------
+ * That's correct, control characters are stored directly in the shared-strings table.
+ * We do encode characters that cannot be represented in XML using the following escape sequence:
+ * _xHHHH_ where H represents a hexadecimal character in the character's value...
+ * So you could end up with something like _x0008_ in a string (either in a cell value ()
+ * element or in the shared string element.
+ *
+ * @param string $value Value to unescape
+ * @return string
+ */
+ public static function ControlCharacterOOXML2PHP($value = '') {
+ return str_replace( array_keys(self::$_controlCharacters), array_values(self::$_controlCharacters), $value );
+ }
+
+ /**
+ * Convert from PHP control character to OpenXML escaped control character
+ *
+ * Excel 2007 team:
+ * ----------------
+ * That's correct, control characters are stored directly in the shared-strings table.
+ * We do encode characters that cannot be represented in XML using the following escape sequence:
+ * _xHHHH_ where H represents a hexadecimal character in the character's value...
+ * So you could end up with something like _x0008_ in a string (either in a cell value ()
+ * element or in the shared string element.
+ *
+ * @param string $value Value to escape
+ * @return string
+ */
+ public static function ControlCharacterPHP2OOXML($value = '') {
+ return str_replace( array_values(self::$_controlCharacters), array_keys(self::$_controlCharacters), $value );
+ }
+
+ /**
+ * Try to sanitize UTF8, stripping invalid byte sequences. Not perfect. Does not surrogate characters.
+ *
+ * @param string $value
+ * @return string
+ */
+ public static function SanitizeUTF8($value)
+ {
+ if (self::getIsIconvEnabled()) {
+ $value = @iconv('UTF-8', 'UTF-8', $value);
+ return $value;
+ }
+
+ if (self::getIsMbstringEnabled()) {
+ $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
+ return $value;
+ }
+
+ // else, no conversion
+ return $value;
+ }
+
+ /**
+ * Check if a string contains UTF8 data
+ *
+ * @param string $value
+ * @return boolean
+ */
+ public static function IsUTF8($value = '') {
+ return $value === '' || preg_match('/^./su', $value) === 1;
+ }
+
+ /**
+ * Formats a numeric value as a string for output in various output writers forcing
+ * point as decimal separator in case locale is other than English.
+ *
+ * @param mixed $value
+ * @return string
+ */
+ public static function FormatNumber($value) {
+ if (is_float($value)) {
+ return str_replace(',', '.', $value);
+ }
+ return (string) $value;
+ }
+
+ /**
+ * Converts a UTF-8 string into BIFF8 Unicode string data (8-bit string length)
+ * Writes the string using uncompressed notation, no rich text, no Asian phonetics
+ * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
+ * although this will give wrong results for non-ASCII strings
+ * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3
+ *
+ * @param string $value UTF-8 encoded string
+ * @param mixed[] $arrcRuns Details of rich text runs in $value
+ * @return string
+ */
+ public static function UTF8toBIFF8UnicodeShort($value, $arrcRuns = array())
+ {
+ // character count
+ $ln = self::CountCharacters($value, 'UTF-8');
+ // option flags
+ if(empty($arrcRuns)){
+ $opt = (self::getIsIconvEnabled() || self::getIsMbstringEnabled()) ?
+ 0x0001 : 0x0000;
+ $data = pack('CC', $ln, $opt);
+ // characters
+ $data .= self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
+ }
+ else {
+ $data = pack('vC', $ln, 0x09);
+ $data .= pack('v', count($arrcRuns));
+ // characters
+ $data .= self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
+ foreach ($arrcRuns as $cRun){
+ $data .= pack('v', $cRun['strlen']);
+ $data .= pack('v', $cRun['fontidx']);
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Converts a UTF-8 string into BIFF8 Unicode string data (16-bit string length)
+ * Writes the string using uncompressed notation, no rich text, no Asian phonetics
+ * If mbstring extension is not available, ASCII is assumed, and compressed notation is used
+ * although this will give wrong results for non-ASCII strings
+ * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3
+ *
+ * @param string $value UTF-8 encoded string
+ * @return string
+ */
+ public static function UTF8toBIFF8UnicodeLong($value)
+ {
+ // character count
+ $ln = self::CountCharacters($value, 'UTF-8');
+
+ // option flags
+ $opt = (self::getIsIconvEnabled() || self::getIsMbstringEnabled()) ?
+ 0x0001 : 0x0000;
+
+ // characters
+ $chars = self::ConvertEncoding($value, 'UTF-16LE', 'UTF-8');
+
+ $data = pack('vC', $ln, $opt) . $chars;
+ return $data;
+ }
+
+ /**
+ * Convert string from one encoding to another. First try mbstring, then iconv, finally strlen
+ *
+ * @param string $value
+ * @param string $to Encoding to convert to, e.g. 'UTF-8'
+ * @param string $from Encoding to convert from, e.g. 'UTF-16LE'
+ * @return string
+ */
+ public static function ConvertEncoding($value, $to, $from)
+ {
+ if (self::getIsIconvEnabled()) {
+ return iconv($from, $to, $value);
+ }
+
+ if (self::getIsMbstringEnabled()) {
+ return mb_convert_encoding($value, $to, $from);
+ }
+
+ if($from == 'UTF-16LE'){
+ return self::utf16_decode($value, false);
+ }else if($from == 'UTF-16BE'){
+ return self::utf16_decode($value);
+ }
+ // else, no conversion
+ return $value;
+ }
+
+ /**
+ * Decode UTF-16 encoded strings.
+ *
+ * Can handle both BOM'ed data and un-BOM'ed data.
+ * Assumes Big-Endian byte order if no BOM is available.
+ * This function was taken from http://php.net/manual/en/function.utf8-decode.php
+ * and $bom_be parameter added.
+ *
+ * @param string $str UTF-16 encoded data to decode.
+ * @return string UTF-8 / ISO encoded data.
+ * @access public
+ * @version 0.2 / 2010-05-13
+ * @author Rasmus Andersson {@link http://rasmusandersson.se/}
+ * @author vadik56
+ */
+ public static function utf16_decode($str, $bom_be = TRUE) {
+ if( strlen($str) < 2 ) return $str;
+ $c0 = ord($str{0});
+ $c1 = ord($str{1});
+ if( $c0 == 0xfe && $c1 == 0xff ) { $str = substr($str,2); }
+ elseif( $c0 == 0xff && $c1 == 0xfe ) { $str = substr($str,2); $bom_be = false; }
+ $len = strlen($str);
+ $newstr = '';
+ for($i=0;$i<$len;$i+=2) {
+ if( $bom_be ) { $val = ord($str{$i}) << 4; $val += ord($str{$i+1}); }
+ else { $val = ord($str{$i+1}) << 4; $val += ord($str{$i}); }
+ $newstr .= ($val == 0x228) ? "\n" : chr($val);
+ }
+ return $newstr;
+ }
+
+ /**
+ * Get character count. First try mbstring, then iconv, finally strlen
+ *
+ * @param string $value
+ * @param string $enc Encoding
+ * @return int Character count
+ */
+ public static function CountCharacters($value, $enc = 'UTF-8')
+ {
+ if (self::getIsMbstringEnabled()) {
+ return mb_strlen($value, $enc);
+ }
+
+ if (self::getIsIconvEnabled()) {
+ return iconv_strlen($value, $enc);
+ }
+
+ // else strlen
+ return strlen($value);
+ }
+
+ /**
+ * Get a substring of a UTF-8 encoded string. First try mbstring, then iconv, finally strlen
+ *
+ * @param string $pValue UTF-8 encoded string
+ * @param int $pStart Start offset
+ * @param int $pLength Maximum number of characters in substring
+ * @return string
+ */
+ public static function Substring($pValue = '', $pStart = 0, $pLength = 0)
+ {
+ if (self::getIsMbstringEnabled()) {
+ return mb_substr($pValue, $pStart, $pLength, 'UTF-8');
+ }
+
+ if (self::getIsIconvEnabled()) {
+ return iconv_substr($pValue, $pStart, $pLength, 'UTF-8');
+ }
+
+ // else substr
+ return substr($pValue, $pStart, $pLength);
+ }
+
+ /**
+ * Convert a UTF-8 encoded string to upper case
+ *
+ * @param string $pValue UTF-8 encoded string
+ * @return string
+ */
+ public static function StrToUpper($pValue = '')
+ {
+ if (function_exists('mb_convert_case')) {
+ return mb_convert_case($pValue, MB_CASE_UPPER, "UTF-8");
+ }
+ return strtoupper($pValue);
+ }
+
+ /**
+ * Convert a UTF-8 encoded string to lower case
+ *
+ * @param string $pValue UTF-8 encoded string
+ * @return string
+ */
+ public static function StrToLower($pValue = '')
+ {
+ if (function_exists('mb_convert_case')) {
+ return mb_convert_case($pValue, MB_CASE_LOWER, "UTF-8");
+ }
+ return strtolower($pValue);
+ }
+
+ /**
+ * Convert a UTF-8 encoded string to title/proper case
+ * (uppercase every first character in each word, lower case all other characters)
+ *
+ * @param string $pValue UTF-8 encoded string
+ * @return string
+ */
+ public static function StrToTitle($pValue = '')
+ {
+ if (function_exists('mb_convert_case')) {
+ return mb_convert_case($pValue, MB_CASE_TITLE, "UTF-8");
+ }
+ return ucwords($pValue);
+ }
+
+ public static function mb_is_upper($char)
+ {
+ return mb_strtolower($char, "UTF-8") != $char;
+ }
+
+ public static function mb_str_split($string)
+ {
+ # Split at all position not after the start: ^
+ # and not before the end: $
+ return preg_split('/(?_calculateFormulaValue($fractionFormula);
+ return true;
+ }
+ return false;
+ } // function convertToNumberIfFraction()
+
+ /**
+ * Get the decimal separator. If it has not yet been set explicitly, try to obtain number
+ * formatting information from locale.
+ *
+ * @return string
+ */
+ public static function getDecimalSeparator()
+ {
+ if (!isset(self::$_decimalSeparator)) {
+ $localeconv = localeconv();
+ self::$_decimalSeparator = ($localeconv['decimal_point'] != '')
+ ? $localeconv['decimal_point'] : $localeconv['mon_decimal_point'];
+
+ if (self::$_decimalSeparator == '') {
+ // Default to .
+ self::$_decimalSeparator = '.';
+ }
+ }
+ return self::$_decimalSeparator;
+ }
+
+ /**
+ * Set the decimal separator. Only used by PHPExcel_Style_NumberFormat::toFormattedString()
+ * to format output by PHPExcel_Writer_HTML and PHPExcel_Writer_PDF
+ *
+ * @param string $pValue Character for decimal separator
+ */
+ public static function setDecimalSeparator($pValue = '.')
+ {
+ self::$_decimalSeparator = $pValue;
+ }
+
+ /**
+ * Get the thousands separator. If it has not yet been set explicitly, try to obtain number
+ * formatting information from locale.
+ *
+ * @return string
+ */
+ public static function getThousandsSeparator()
+ {
+ if (!isset(self::$_thousandsSeparator)) {
+ $localeconv = localeconv();
+ self::$_thousandsSeparator = ($localeconv['thousands_sep'] != '')
+ ? $localeconv['thousands_sep'] : $localeconv['mon_thousands_sep'];
+
+ if (self::$_thousandsSeparator == '') {
+ // Default to .
+ self::$_thousandsSeparator = ',';
+ }
+ }
+ return self::$_thousandsSeparator;
+ }
+
+ /**
+ * Set the thousands separator. Only used by PHPExcel_Style_NumberFormat::toFormattedString()
+ * to format output by PHPExcel_Writer_HTML and PHPExcel_Writer_PDF
+ *
+ * @param string $pValue Character for thousands separator
+ */
+ public static function setThousandsSeparator($pValue = ',')
+ {
+ self::$_thousandsSeparator = $pValue;
+ }
+
+ /**
+ * Get the currency code. If it has not yet been set explicitly, try to obtain the
+ * symbol information from locale.
+ *
+ * @return string
+ */
+ public static function getCurrencyCode()
+ {
+ if (!isset(self::$_currencyCode)) {
+ $localeconv = localeconv();
+ self::$_currencyCode = ($localeconv['currency_symbol'] != '')
+ ? $localeconv['currency_symbol'] : $localeconv['int_curr_symbol'];
+
+ if (self::$_currencyCode == '') {
+ // Default to $
+ self::$_currencyCode = '$';
+ }
+ }
+ return self::$_currencyCode;
+ }
+
+ /**
+ * Set the currency code. Only used by PHPExcel_Style_NumberFormat::toFormattedString()
+ * to format output by PHPExcel_Writer_HTML and PHPExcel_Writer_PDF
+ *
+ * @param string $pValue Character for currency code
+ */
+ public static function setCurrencyCode($pValue = '$')
+ {
+ self::$_currencyCode = $pValue;
+ }
+
+ /**
+ * Convert SYLK encoded string to UTF-8
+ *
+ * @param string $pValue
+ * @return string UTF-8 encoded string
+ */
+ public static function SYLKtoUTF8($pValue = '')
+ {
+ // If there is no escape character in the string there is nothing to do
+ if (strpos($pValue, '') === false) {
+ return $pValue;
+ }
+
+ foreach (self::$_SYLKCharacters as $k => $v) {
+ $pValue = str_replace($k, $v, $pValue);
+ }
+
+ return $pValue;
+ }
+
+ /**
+ * Retrieve any leading numeric part of a string, or return the full string if no leading numeric
+ * (handles basic integer or float, but not exponent or non decimal)
+ *
+ * @param string $value
+ * @return mixed string or only the leading numeric part of the string
+ */
+ public static function testStringAsNumeric($value)
+ {
+ if (is_numeric($value))
+ return $value;
+ $v = floatval($value);
+ return (is_numeric(substr($value, 0, strlen($v)))) ? $v : $value;
+ }
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/TimeZone.php b/includes/PHPExcel/Classes/PHPExcel/Shared/TimeZone.php
new file mode 100644
index 0000000..1792a29
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/TimeZone.php
@@ -0,0 +1,140 @@
+getTransitions();
+ $transitions = array();
+ foreach($allTransitions as $key => $transition) {
+ if ($transition['ts'] > $timestamp) {
+ $transitions[] = ($key > 0) ? $allTransitions[$key - 1] : $transition;
+ break;
+ }
+ if (empty($transitions)) {
+ $transitions[] = end($allTransitions);
+ }
+ }
+
+ return $transitions;
+ }
+
+ /**
+ * Return the Timezone offset used for date/time conversions to/from UST
+ * This requires both the timezone and the calculated date/time to allow for local DST
+ *
+ * @param string $timezone The timezone for finding the adjustment to UST
+ * @param integer $timestamp PHP date/time value
+ * @return integer Number of seconds for timezone adjustment
+ * @throws PHPExcel_Exception
+ */
+ public static function getTimeZoneAdjustment($timezone, $timestamp) {
+ if ($timezone !== NULL) {
+ if (!self::_validateTimezone($timezone)) {
+ throw new PHPExcel_Exception("Invalid timezone " . $timezone);
+ }
+ } else {
+ $timezone = self::$_timezone;
+ }
+
+ if ($timezone == 'UST') {
+ return 0;
+ }
+
+ $objTimezone = new DateTimeZone($timezone);
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
+ $transitions = $objTimezone->getTransitions($timestamp,$timestamp);
+ } else {
+ $transitions = self::_getTimezoneTransitions($objTimezone, $timestamp);
+ }
+
+ return (count($transitions) > 0) ? $transitions[0]['offset'] : 0;
+ }
+
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/XMLWriter.php b/includes/PHPExcel/Classes/PHPExcel/Shared/XMLWriter.php
new file mode 100644
index 0000000..beca51f
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/XMLWriter.php
@@ -0,0 +1,127 @@
+openMemory();
+ } else {
+ // Create temporary filename
+ if ($pTemporaryStorageFolder === NULL)
+ $pTemporaryStorageFolder = PHPExcel_Shared_File::sys_get_temp_dir();
+ $this->_tempFileName = @tempnam($pTemporaryStorageFolder, 'xml');
+
+ // Open storage
+ if ($this->openUri($this->_tempFileName) === false) {
+ // Fallback to memory...
+ $this->openMemory();
+ }
+ }
+
+ // Set default values
+ if (DEBUGMODE_ENABLED) {
+ $this->setIndent(true);
+ }
+ }
+
+ /**
+ * Destructor
+ */
+ public function __destruct() {
+ // Unlink temporary files
+ if ($this->_tempFileName != '') {
+ @unlink($this->_tempFileName);
+ }
+ }
+
+ /**
+ * Get written data
+ *
+ * @return $data
+ */
+ public function getData() {
+ if ($this->_tempFileName == '') {
+ return $this->outputMemory(true);
+ } else {
+ $this->flush();
+ return file_get_contents($this->_tempFileName);
+ }
+ }
+
+ /**
+ * Fallback method for writeRaw, introduced in PHP 5.2
+ *
+ * @param string $text
+ * @return string
+ */
+ public function writeRawData($text)
+ {
+ if (is_array($text)) {
+ $text = implode("\n",$text);
+ }
+
+ if (method_exists($this, 'writeRaw')) {
+ return $this->writeRaw(htmlspecialchars($text));
+ }
+
+ return $this->text($text);
+ }
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/ZipArchive.php b/includes/PHPExcel/Classes/PHPExcel/Shared/ZipArchive.php
new file mode 100644
index 0000000..9a801a8
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/ZipArchive.php
@@ -0,0 +1,175 @@
+_tempDir = PHPExcel_Shared_File::sys_get_temp_dir();
+
+ $this->_zip = new PclZip($fileName);
+
+ return true;
+ }
+
+
+ /**
+ * Close this zip archive
+ *
+ */
+ public function close()
+ {
+ }
+
+
+ /**
+ * Add a new file to the zip archive from a string of raw data.
+ *
+ * @param string $localname Directory/Name of the file to add to the zip archive
+ * @param string $contents String of data to add to the zip archive
+ */
+ public function addFromString($localname, $contents)
+ {
+ $filenameParts = pathinfo($localname);
+
+ $handle = fopen($this->_tempDir.'/'.$filenameParts["basename"], "wb");
+ fwrite($handle, $contents);
+ fclose($handle);
+
+ $res = $this->_zip->add($this->_tempDir.'/'.$filenameParts["basename"],
+ PCLZIP_OPT_REMOVE_PATH, $this->_tempDir,
+ PCLZIP_OPT_ADD_PATH, $filenameParts["dirname"]
+ );
+ if ($res == 0) {
+ throw new PHPExcel_Writer_Exception("Error zipping files : " . $this->_zip->errorInfo(true));
+ }
+
+ unlink($this->_tempDir.'/'.$filenameParts["basename"]);
+ }
+
+ /**
+ * Find if given fileName exist in archive (Emulate ZipArchive locateName())
+ *
+ * @param string $fileName Filename for the file in zip archive
+ * @return boolean
+ */
+ public function locateName($fileName)
+ {
+ $list = $this->_zip->listContent();
+ $listCount = count($list);
+ $list_index = -1;
+ for ($i = 0; $i < $listCount; ++$i) {
+ if (strtolower($list[$i]["filename"]) == strtolower($fileName) ||
+ strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) {
+ $list_index = $i;
+ break;
+ }
+ }
+ return ($list_index > -1);
+ }
+
+ /**
+ * Extract file from archive by given fileName (Emulate ZipArchive getFromName())
+ *
+ * @param string $fileName Filename for the file in zip archive
+ * @return string $contents File string contents
+ */
+ public function getFromName($fileName)
+ {
+ $list = $this->_zip->listContent();
+ $listCount = count($list);
+ $list_index = -1;
+ for ($i = 0; $i < $listCount; ++$i) {
+ if (strtolower($list[$i]["filename"]) == strtolower($fileName) ||
+ strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) {
+ $list_index = $i;
+ break;
+ }
+ }
+
+ $extracted = "";
+ if ($list_index != -1) {
+ $extracted = $this->_zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING);
+ } else {
+ $filename = substr($fileName, 1);
+ $list_index = -1;
+ for ($i = 0; $i < $listCount; ++$i) {
+ if (strtolower($list[$i]["filename"]) == strtolower($fileName) ||
+ strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) {
+ $list_index = $i;
+ break;
+ }
+ }
+ $extracted = $this->_zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING);
+ }
+ if ((is_array($extracted)) && ($extracted != 0)) {
+ $contents = $extracted[0]["content"];
+ }
+
+ return $contents;
+ }
+}
diff --git a/includes/PHPExcel/Classes/PHPExcel/Shared/ZipStreamWrapper.php b/includes/PHPExcel/Classes/PHPExcel/Shared/ZipStreamWrapper.php
new file mode 100644
index 0000000..6e63d3c
--- /dev/null
+++ b/includes/PHPExcel/Classes/PHPExcel/Shared/ZipStreamWrapper.php
@@ -0,0 +1,201 @@
+_archive = new ZipArchive();
+ $this->_archive->open($url['host']);
+
+ $this->_fileNameInArchive = $url['fragment'];
+ $this->_position = 0;
+ $this->_data = $this->_archive->getFromName( $this->_fileNameInArchive );
+
+ return true;
+ }
+
+ /**
+ * Implements support for fstat().
+ *
+ * @return boolean
+ */
+ public function statName() {
+ return $this->_fileNameInArchive;
+ }
+
+ /**
+ * Implements support for fstat().
+ *
+ * @return boolean
+ */
+ public function url_stat() {
+ return $this->statName( $this->_fileNameInArchive );
+ }
+
+ /**
+ * Implements support for fstat().
+ *
+ * @return boolean
+ */
+ public function stream_stat() {
+ return $this->_archive->statName( $this->_fileNameInArchive );
+ }
+
+ /**
+ * Implements support for fread(), fgets() etc.
+ *
+ * @param int $count maximum number of bytes to read
+ * @return string
+ */
+ function stream_read($count) {
+ $ret = substr($this->_data, $this->_position, $count);
+ $this->_position += strlen($ret);
+ return $ret;
+ }
+
+ /**
+ * Returns the position of the file pointer, i.e. its offset into the file
+ * stream. Implements support for ftell().
+ *
+ * @return int
+ */
+ public function stream_tell() {
+ return $this->_position;
+ }
+
+ /**
+ * EOF stream
+ *
+ * @return bool
+ */
+ public function stream_eof() {
+ return $this->_position >= strlen($this->_data);
+ }
+
+ /**
+ * Seek stream
+ *
+ * @param int $offset byte offset
+ * @param int $whence SEEK_SET, SEEK_CUR or SEEK_END
+ * @return bool
+ */
+ public function stream_seek($offset, $whence) {
+ switch ($whence) {
+ case SEEK_SET:
+ if ($offset < strlen($this->_data) && $offset >= 0) {
+ $this->_position = $offset;
+ return true;
+ } else {
+ return false;
+ }
+ break;
+
+ case SEEK_CUR:
+ if ($offset >= 0) {
+ $this->_position += $offset;
+ return true;
+ } else {
+ return false;
+ }
+ break;
+
+ case SEEK_END:
+ if (strlen($this->_data) + $offset >= 0) {
+ $this->_position = strlen($this->_data) + $offset;
+ return true;
+ } else {
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+ }
+}