Dateien nach "includes/PHPExcel/Classes/PHPExcel/Shared" hochladen
This commit is contained in:
parent
4fbeddb566
commit
dee2b769b1
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_CodePage
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_CodePage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Convert Microsoft Code Page Identifier to Code Page Name which iconv
|
||||||
|
* and mbstring understands
|
||||||
|
*
|
||||||
|
* @param integer $codePage Microsoft Code Page Indentifier
|
||||||
|
* @return string Code Page Name
|
||||||
|
* @throws PHPExcel_Exception
|
||||||
|
*/
|
||||||
|
public static function NumberToName($codePage = 1252)
|
||||||
|
{
|
||||||
|
switch ($codePage) {
|
||||||
|
case 367: return 'ASCII'; break; // ASCII
|
||||||
|
case 437: return 'CP437'; break; // OEM US
|
||||||
|
case 720: throw new PHPExcel_Exception('Code page 720 not supported.');
|
||||||
|
break; // OEM Arabic
|
||||||
|
case 737: return 'CP737'; break; // OEM Greek
|
||||||
|
case 775: return 'CP775'; break; // OEM Baltic
|
||||||
|
case 850: return 'CP850'; break; // OEM Latin I
|
||||||
|
case 852: return 'CP852'; break; // OEM Latin II (Central European)
|
||||||
|
case 855: return 'CP855'; break; // OEM Cyrillic
|
||||||
|
case 857: return 'CP857'; break; // OEM Turkish
|
||||||
|
case 858: return 'CP858'; break; // OEM Multilingual Latin I with Euro
|
||||||
|
case 860: return 'CP860'; break; // OEM Portugese
|
||||||
|
case 861: return 'CP861'; break; // OEM Icelandic
|
||||||
|
case 862: return 'CP862'; break; // OEM Hebrew
|
||||||
|
case 863: return 'CP863'; break; // OEM Canadian (French)
|
||||||
|
case 864: return 'CP864'; break; // OEM Arabic
|
||||||
|
case 865: return 'CP865'; break; // OEM Nordic
|
||||||
|
case 866: return 'CP866'; break; // OEM Cyrillic (Russian)
|
||||||
|
case 869: return 'CP869'; break; // OEM Greek (Modern)
|
||||||
|
case 874: return 'CP874'; break; // ANSI Thai
|
||||||
|
case 932: return 'CP932'; break; // ANSI Japanese Shift-JIS
|
||||||
|
case 936: return 'CP936'; break; // ANSI Chinese Simplified GBK
|
||||||
|
case 949: return 'CP949'; break; // ANSI Korean (Wansung)
|
||||||
|
case 950: return 'CP950'; break; // ANSI Chinese Traditional BIG5
|
||||||
|
case 1200: return 'UTF-16LE'; break; // UTF-16 (BIFF8)
|
||||||
|
case 1250: return 'CP1250'; break; // ANSI Latin II (Central European)
|
||||||
|
case 1251: return 'CP1251'; break; // ANSI Cyrillic
|
||||||
|
case 0: // CodePage is not always correctly set when the xls file was saved by Apple's Numbers program
|
||||||
|
case 1252: return 'CP1252'; break; // ANSI Latin I (BIFF4-BIFF7)
|
||||||
|
case 1253: return 'CP1253'; break; // ANSI Greek
|
||||||
|
case 1254: return 'CP1254'; break; // ANSI Turkish
|
||||||
|
case 1255: return 'CP1255'; break; // ANSI Hebrew
|
||||||
|
case 1256: return 'CP1256'; break; // ANSI Arabic
|
||||||
|
case 1257: return 'CP1257'; break; // ANSI Baltic
|
||||||
|
case 1258: return 'CP1258'; break; // ANSI Vietnamese
|
||||||
|
case 1361: return 'CP1361'; break; // ANSI Korean (Johab)
|
||||||
|
case 10000: return 'MAC'; break; // Apple Roman
|
||||||
|
case 10001: return 'CP932'; break; // Macintosh Japanese
|
||||||
|
case 10002: return 'CP950'; break; // Macintosh Chinese Traditional
|
||||||
|
case 10003: return 'CP1361'; break; // Macintosh Korean
|
||||||
|
case 10006: return 'MACGREEK'; break; // Macintosh Greek
|
||||||
|
case 10007: return 'MACCYRILLIC'; break; // Macintosh Cyrillic
|
||||||
|
case 10008: return 'CP936'; break; // Macintosh - Simplified Chinese (GB 2312)
|
||||||
|
case 10029: return 'MACCENTRALEUROPE'; break; // Macintosh Central Europe
|
||||||
|
case 10079: return 'MACICELAND'; break; // Macintosh Icelandic
|
||||||
|
case 10081: return 'MACTURKISH'; break; // Macintosh Turkish
|
||||||
|
case 21010: return 'UTF-16LE'; break; // UTF-16 (BIFF8) This isn't correct, but some Excel writer libraries erroneously use Codepage 21010 for UTF-16LE
|
||||||
|
case 32768: return 'MAC'; break; // Apple Roman
|
||||||
|
case 32769: throw new PHPExcel_Exception('Code page 32769 not supported.');
|
||||||
|
break; // ANSI Latin I (BIFF2-BIFF3)
|
||||||
|
case 65000: return 'UTF-7'; break; // Unicode (UTF-7)
|
||||||
|
case 65001: return 'UTF-8'; break; // Unicode (UTF-8)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PHPExcel_Exception('Unknown codepage: ' . $codePage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,393 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_Date
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_Date
|
||||||
|
{
|
||||||
|
/** constants */
|
||||||
|
const CALENDAR_WINDOWS_1900 = 1900; // Base date of 1st Jan 1900 = 1.0
|
||||||
|
const CALENDAR_MAC_1904 = 1904; // Base date of 2nd Jan 1904 = 1.0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Names of the months of the year, indexed by shortname
|
||||||
|
* Planned usage for locale settings
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
public static $_monthNames = array( 'Jan' => '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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,272 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_Drawing
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_Drawing
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Convert pixels to EMU
|
||||||
|
*
|
||||||
|
* @param int $pValue Value in pixels
|
||||||
|
* @return int Value in EMU
|
||||||
|
*/
|
||||||
|
public static function pixelsToEMU($pValue = 0) {
|
||||||
|
return round($pValue * 9525);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert EMU to pixels
|
||||||
|
*
|
||||||
|
* @param int $pValue Value in EMU
|
||||||
|
* @return int Value in pixels
|
||||||
|
*/
|
||||||
|
public static function EMUToPixels($pValue = 0) {
|
||||||
|
if ($pValue != 0) {
|
||||||
|
return round($pValue / 9525);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert pixels to column width. Exact algorithm not known.
|
||||||
|
* By inspection of a real Excel file using Calibri 11, one finds 1000px ~ 142.85546875
|
||||||
|
* This gives a conversion factor of 7. Also, we assume that pixels and font size are proportional.
|
||||||
|
*
|
||||||
|
* @param int $pValue Value in pixels
|
||||||
|
* @param PHPExcel_Style_Font $pDefaultFont Default font of the workbook
|
||||||
|
* @return int Value in cell dimension
|
||||||
|
*/
|
||||||
|
public static function pixelsToCellDimension($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]['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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared_Escher
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_Escher
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared_Escher
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_Escher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Drawing Group Container
|
||||||
|
*
|
||||||
|
* @var PHPExcel_Shared_Escher_DggContainer
|
||||||
|
*/
|
||||||
|
private $_dggContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawing Container
|
||||||
|
*
|
||||||
|
* @var PHPExcel_Shared_Escher_DgContainer
|
||||||
|
*/
|
||||||
|
private $_dgContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Drawing Group Container
|
||||||
|
*
|
||||||
|
* @return PHPExcel_Shared_Escher_DgContainer
|
||||||
|
*/
|
||||||
|
public function getDggContainer()
|
||||||
|
{
|
||||||
|
return $this->_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,317 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_Excel5
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_Excel5
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the width of a column in pixels. We use the relationship y = ceil(7x) where
|
||||||
|
* x is the width in intrinsic Excel units (measuring width in number of normal characters)
|
||||||
|
* This holds for Arial 10
|
||||||
|
*
|
||||||
|
* @param PHPExcel_Worksheet $sheet The sheet
|
||||||
|
* @param string $col The column
|
||||||
|
* @return integer The width in pixels
|
||||||
|
*/
|
||||||
|
public static function sizeCol($sheet, $col = 'A')
|
||||||
|
{
|
||||||
|
// default font of the workbook
|
||||||
|
$font = $sheet->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_File
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_File
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Use Temp or File Upload Temp for temporary files
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected static $_useUploadTempDirectory = FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the flag indicating whether the File Upload Temp directory should be used for temporary files
|
||||||
|
*
|
||||||
|
* @param boolean $useUploadTempDir Use File Upload Temporary directory (true or false)
|
||||||
|
*/
|
||||||
|
public static function setUseUploadTempDirectory($useUploadTempDir = FALSE) {
|
||||||
|
self::$_useUploadTempDirectory = (boolean) $useUploadTempDir;
|
||||||
|
} // function setUseUploadTempDirectory()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the flag indicating whether the File Upload Temp directory should be used for temporary files
|
||||||
|
*
|
||||||
|
* @return boolean Use File Upload Temporary directory (true or false)
|
||||||
|
*/
|
||||||
|
public static function getUseUploadTempDirectory() {
|
||||||
|
return self::$_useUploadTempDirectory;
|
||||||
|
} // function getUseUploadTempDirectory()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify if a file exists
|
||||||
|
*
|
||||||
|
* @param string $pFilename Filename
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function file_exists($pFilename) {
|
||||||
|
// Sick construction, but it seems that
|
||||||
|
// file_exists returns strange values when
|
||||||
|
// doing the original file_exists on ZIP archives...
|
||||||
|
if ( strtolower(substr($pFilename, 0, 3)) == 'zip' ) {
|
||||||
|
// Open ZIP file and verify if the file exists
|
||||||
|
$zipFile = substr($pFilename, 6, strpos($pFilename, '#') - 6);
|
||||||
|
$archiveFile = substr($pFilename, strpos($pFilename, '#') + 1);
|
||||||
|
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
if ($zip->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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,773 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_Font
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_Font
|
||||||
|
{
|
||||||
|
/* Methods for resolving autosize value */
|
||||||
|
const AUTOSIZE_METHOD_APPROX = 'approx';
|
||||||
|
const AUTOSIZE_METHOD_EXACT = 'exact';
|
||||||
|
|
||||||
|
private static $_autoSizeMethods = array(
|
||||||
|
self::AUTOSIZE_METHOD_APPROX,
|
||||||
|
self::AUTOSIZE_METHOD_EXACT,
|
||||||
|
);
|
||||||
|
|
||||||
|
/** Character set codes used by BIFF5-8 in Font records */
|
||||||
|
const CHARSET_ANSI_LATIN = 0x00;
|
||||||
|
const CHARSET_SYSTEM_DEFAULT = 0x01;
|
||||||
|
const CHARSET_SYMBOL = 0x02;
|
||||||
|
const CHARSET_APPLE_ROMAN = 0x4D;
|
||||||
|
const CHARSET_ANSI_JAPANESE_SHIFTJIS = 0x80;
|
||||||
|
const CHARSET_ANSI_KOREAN_HANGUL = 0x81;
|
||||||
|
const CHARSET_ANSI_KOREAN_JOHAB = 0x82;
|
||||||
|
const CHARSET_ANSI_CHINESE_SIMIPLIFIED = 0x86; // gb2312
|
||||||
|
const CHARSET_ANSI_CHINESE_TRADITIONAL = 0x88; // big5
|
||||||
|
const CHARSET_ANSI_GREEK = 0xA1;
|
||||||
|
const CHARSET_ANSI_TURKISH = 0xA2;
|
||||||
|
const CHARSET_ANSI_VIETNAMESE = 0xA3;
|
||||||
|
const CHARSET_ANSI_HEBREW = 0xB1;
|
||||||
|
const CHARSET_ANSI_ARABIC = 0xB2;
|
||||||
|
const CHARSET_ANSI_BALTIC = 0xBA;
|
||||||
|
const CHARSET_ANSI_CYRILLIC = 0xCC;
|
||||||
|
const CHARSET_ANSI_THAI = 0xDD;
|
||||||
|
const CHARSET_ANSI_LATIN_II = 0xEE;
|
||||||
|
const CHARSET_OEM_LATIN_I = 0xFF;
|
||||||
|
|
||||||
|
// XXX: Constants created!
|
||||||
|
/** Font filenames */
|
||||||
|
const ARIAL = 'arial.ttf';
|
||||||
|
const ARIAL_BOLD = 'arialbd.ttf';
|
||||||
|
const ARIAL_ITALIC = 'ariali.ttf';
|
||||||
|
const ARIAL_BOLD_ITALIC = 'arialbi.ttf';
|
||||||
|
|
||||||
|
const CALIBRI = 'CALIBRI.TTF';
|
||||||
|
const CALIBRI_BOLD = 'CALIBRIB.TTF';
|
||||||
|
const CALIBRI_ITALIC = 'CALIBRII.TTF';
|
||||||
|
const CALIBRI_BOLD_ITALIC = 'CALIBRIZ.TTF';
|
||||||
|
|
||||||
|
const COMIC_SANS_MS = 'comic.ttf';
|
||||||
|
const COMIC_SANS_MS_BOLD = 'comicbd.ttf';
|
||||||
|
|
||||||
|
const COURIER_NEW = 'cour.ttf';
|
||||||
|
const COURIER_NEW_BOLD = 'courbd.ttf';
|
||||||
|
const COURIER_NEW_ITALIC = 'couri.ttf';
|
||||||
|
const COURIER_NEW_BOLD_ITALIC = 'courbi.ttf';
|
||||||
|
|
||||||
|
const GEORGIA = 'georgia.ttf';
|
||||||
|
const GEORGIA_BOLD = 'georgiab.ttf';
|
||||||
|
const GEORGIA_ITALIC = 'georgiai.ttf';
|
||||||
|
const GEORGIA_BOLD_ITALIC = 'georgiaz.ttf';
|
||||||
|
|
||||||
|
const IMPACT = 'impact.ttf';
|
||||||
|
|
||||||
|
const LIBERATION_SANS = 'LiberationSans-Regular.ttf';
|
||||||
|
const LIBERATION_SANS_BOLD = 'LiberationSans-Bold.ttf';
|
||||||
|
const LIBERATION_SANS_ITALIC = 'LiberationSans-Italic.ttf';
|
||||||
|
const LIBERATION_SANS_BOLD_ITALIC = 'LiberationSans-BoldItalic.ttf';
|
||||||
|
|
||||||
|
const LUCIDA_CONSOLE = 'lucon.ttf';
|
||||||
|
const LUCIDA_SANS_UNICODE = 'l_10646.ttf';
|
||||||
|
|
||||||
|
const MICROSOFT_SANS_SERIF = 'micross.ttf';
|
||||||
|
|
||||||
|
const PALATINO_LINOTYPE = 'pala.ttf';
|
||||||
|
const PALATINO_LINOTYPE_BOLD = 'palab.ttf';
|
||||||
|
const PALATINO_LINOTYPE_ITALIC = 'palai.ttf';
|
||||||
|
const PALATINO_LINOTYPE_BOLD_ITALIC = 'palabi.ttf';
|
||||||
|
|
||||||
|
const SYMBOL = 'symbol.ttf';
|
||||||
|
|
||||||
|
const TAHOMA = 'tahoma.ttf';
|
||||||
|
const TAHOMA_BOLD = 'tahomabd.ttf';
|
||||||
|
|
||||||
|
const TIMES_NEW_ROMAN = 'times.ttf';
|
||||||
|
const TIMES_NEW_ROMAN_BOLD = 'timesbd.ttf';
|
||||||
|
const TIMES_NEW_ROMAN_ITALIC = 'timesi.ttf';
|
||||||
|
const TIMES_NEW_ROMAN_BOLD_ITALIC = 'timesbi.ttf';
|
||||||
|
|
||||||
|
const TREBUCHET_MS = 'trebuc.ttf';
|
||||||
|
const TREBUCHET_MS_BOLD = 'trebucbd.ttf';
|
||||||
|
const TREBUCHET_MS_ITALIC = 'trebucit.ttf';
|
||||||
|
const TREBUCHET_MS_BOLD_ITALIC = 'trebucbi.ttf';
|
||||||
|
|
||||||
|
const VERDANA = 'verdana.ttf';
|
||||||
|
const VERDANA_BOLD = 'verdanab.ttf';
|
||||||
|
const VERDANA_ITALIC = 'verdanai.ttf';
|
||||||
|
const VERDANA_BOLD_ITALIC = 'verdanaz.ttf';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoSize method
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $autoSizeMethod = self::AUTOSIZE_METHOD_APPROX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to folder containing TrueType font .ttf files
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $trueTypeFontPath = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How wide is a default column for a given default font and size?
|
||||||
|
* Empirical data found by inspecting real Excel files and reading off the pixel width
|
||||||
|
* in Microsoft Office Excel 2007.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $defaultColumnWidths = array(
|
||||||
|
'Arial' => 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:
|
||||||
|
* <ul>
|
||||||
|
* <li>C:/Windows/Fonts/</li>
|
||||||
|
* <li>/usr/share/fonts/truetype/</li>
|
||||||
|
* <li>~/.fonts/</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,531 @@
|
||||||
|
<?php
|
||||||
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | PHP Version 4 |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 1997-2002 The PHP Group |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | This source file is subject to version 2.02 of the PHP license, |
|
||||||
|
// | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
// | available at through the world-wide-web at |
|
||||||
|
// | http://www.php.net/license/2_02.txt. |
|
||||||
|
// | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
// | obtain it through the world-wide-web, please send a note to |
|
||||||
|
// | license@php.net so we can mail you a copy immediately. |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Author: Xavier Noguer <xnoguer@php.net> |
|
||||||
|
// | 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 <xnoguer@php.net>
|
||||||
|
* @author Christian Schmidt <schmidt@php.net>
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,317 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('IDENTIFIER_OLE') ||
|
||||||
|
define('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
|
||||||
|
|
||||||
|
class PHPExcel_Shared_OLERead {
|
||||||
|
private $data = '';
|
||||||
|
|
||||||
|
// OLE identifier
|
||||||
|
const IDENTIFIER_OLE = IDENTIFIER_OLE;
|
||||||
|
|
||||||
|
// Size of a sector = 512 bytes
|
||||||
|
const BIG_BLOCK_SIZE = 0x200;
|
||||||
|
|
||||||
|
// Size of a short sector = 64 bytes
|
||||||
|
const SMALL_BLOCK_SIZE = 0x40;
|
||||||
|
|
||||||
|
// Size of a directory entry always = 128 bytes
|
||||||
|
const PROPERTY_STORAGE_BLOCK_SIZE = 0x80;
|
||||||
|
|
||||||
|
// Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams
|
||||||
|
const SMALL_BLOCK_THRESHOLD = 0x1000;
|
||||||
|
|
||||||
|
// header offsets
|
||||||
|
const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
|
||||||
|
const ROOT_START_BLOCK_POS = 0x30;
|
||||||
|
const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
|
||||||
|
const EXTENSION_BLOCK_POS = 0x44;
|
||||||
|
const NUM_EXTENSION_BLOCK_POS = 0x48;
|
||||||
|
const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;
|
||||||
|
|
||||||
|
// property storage offsets (directory offsets)
|
||||||
|
const SIZE_OF_NAME_POS = 0x40;
|
||||||
|
const TYPE_POS = 0x42;
|
||||||
|
const START_BLOCK_POS = 0x74;
|
||||||
|
const SIZE_POS = 0x78;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public $wrkbook = null;
|
||||||
|
public $summaryInformation = null;
|
||||||
|
public $documentSummaryInformation = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the file
|
||||||
|
*
|
||||||
|
* @param $sFileName string Filename
|
||||||
|
* @throws PHPExcel_Reader_Exception
|
||||||
|
*/
|
||||||
|
public function read($sFileName)
|
||||||
|
{
|
||||||
|
// Check if file exists and is readable
|
||||||
|
if(!is_readable($sFileName)) {
|
||||||
|
throw new PHPExcel_Reader_Exception("Could not open " . $sFileName . " for reading! File does not exist, or it is not readable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the file identifier
|
||||||
|
// Don't bother reading the whole file until we know it's a valid OLE file
|
||||||
|
$this->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<br />';
|
||||||
|
$this->summaryInformation = count($this->props) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional Document Summary information
|
||||||
|
if ($name == chr(5) . 'DocumentSummaryInformation') {
|
||||||
|
// echo 'Document Summary Information<br />';
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_PasswordHasher
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_PasswordHasher
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a password hash from a given string.
|
||||||
|
*
|
||||||
|
* This method is based on the algorithm provided by
|
||||||
|
* Daniel Rentz of OpenOffice and the PEAR package
|
||||||
|
* Spreadsheet_Excel_Writer by Xavier Noguer <xnoguer@rezebra.com>.
|
||||||
|
*
|
||||||
|
* @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)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,811 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_String
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_String
|
||||||
|
{
|
||||||
|
/** Constants */
|
||||||
|
/** Regular Expressions */
|
||||||
|
// Fraction
|
||||||
|
const STRING_REGEXP_FRACTION = '(-?)(\d+)\s+(\d+\/\d+)';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control characters array
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private static $_controlCharacters = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SYLK Characters array
|
||||||
|
*
|
||||||
|
* $var array
|
||||||
|
*/
|
||||||
|
private static $_SYLKCharacters = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decimal separator
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $_decimalSeparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thousands separator
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $_thousandsSeparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currency code
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $_currencyCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is mbstring extension avalable?
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private static $_isMbstringEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is iconv extension avalable?
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private static $_isIconvEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build control characters array
|
||||||
|
*/
|
||||||
|
private static function _buildControlCharacters() {
|
||||||
|
for ($i = 0; $i <= 31; ++$i) {
|
||||||
|
if ($i != 9 && $i != 10 && $i != 13) {
|
||||||
|
$find = '_x' . sprintf('%04s' , strtoupper(dechex($i))) . '_';
|
||||||
|
$replace = chr($i);
|
||||||
|
self::$_controlCharacters[$find] = $replace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build SYLK characters array
|
||||||
|
*/
|
||||||
|
private static function _buildSYLKCharacters()
|
||||||
|
{
|
||||||
|
self::$_SYLKCharacters = array(
|
||||||
|
"\x1B 0" => 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 (<v>)
|
||||||
|
* element or in the shared string <t> 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 (<v>)
|
||||||
|
* element or in the shared string <t> 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('/(?<!^)(?!$)/u', $string );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the case of a string, so that all uppercase characters become lowercase
|
||||||
|
* and all lowercase characters become uppercase
|
||||||
|
*
|
||||||
|
* @param string $pValue UTF-8 encoded string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function StrCaseReverse($pValue = '')
|
||||||
|
{
|
||||||
|
if (self::getIsMbstringEnabled()) {
|
||||||
|
$characters = self::mb_str_split($pValue);
|
||||||
|
foreach($characters as &$character) {
|
||||||
|
if(self::mb_is_upper($character)) {
|
||||||
|
$character = mb_strtolower($character, 'UTF-8');
|
||||||
|
} else {
|
||||||
|
$character = mb_strtoupper($character, 'UTF-8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implode('', $characters);
|
||||||
|
}
|
||||||
|
return strtolower($pValue) ^ strtoupper($pValue) ^ $pValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify whether a string contains a fractional numeric value,
|
||||||
|
* and convert it to a numeric if it is
|
||||||
|
*
|
||||||
|
* @param string &$operand string value to test
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function convertToNumberIfFraction(&$operand) {
|
||||||
|
if (preg_match('/^'.self::STRING_REGEXP_FRACTION.'$/i', $operand, $match)) {
|
||||||
|
$sign = ($match[1] == '-') ? '-' : '+';
|
||||||
|
$fractionFormula = '='.$sign.$match[2].$sign.$match[3];
|
||||||
|
$operand = PHPExcel_Calculation::getInstance()->_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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_TimeZone
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_TimeZone
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Default Timezone used for date/time conversions
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $_timezone = 'UTC';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a Timezone name
|
||||||
|
*
|
||||||
|
* @param string $timezone Time zone (e.g. 'Europe/London')
|
||||||
|
* @return boolean Success or failure
|
||||||
|
*/
|
||||||
|
public static function _validateTimeZone($timezone) {
|
||||||
|
if (in_array($timezone, DateTimeZone::listIdentifiers())) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Default Timezone used for date/time conversions
|
||||||
|
*
|
||||||
|
* @param string $timezone Time zone (e.g. 'Europe/London')
|
||||||
|
* @return boolean Success or failure
|
||||||
|
*/
|
||||||
|
public static function setTimeZone($timezone) {
|
||||||
|
if (self::_validateTimezone($timezone)) {
|
||||||
|
self::$_timezone = $timezone;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
} // function setTimezone()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Default Timezone used for date/time conversions
|
||||||
|
*
|
||||||
|
* @return string Timezone (e.g. 'Europe/London')
|
||||||
|
*/
|
||||||
|
public static function getTimeZone() {
|
||||||
|
return self::$_timezone;
|
||||||
|
} // function getTimezone()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Timezone transition for the specified timezone and timestamp
|
||||||
|
*
|
||||||
|
* @param DateTimeZone $objTimezone The timezone for finding the transitions
|
||||||
|
* @param integer $timestamp PHP date/time value for finding the current transition
|
||||||
|
* @return array The current transition details
|
||||||
|
*/
|
||||||
|
private static function _getTimezoneTransitions($objTimezone, $timestamp) {
|
||||||
|
$allTransitions = $objTimezone->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('DATE_W3C')) {
|
||||||
|
define('DATE_W3C', 'Y-m-d\TH:i:sP');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('DEBUGMODE_ENABLED')) {
|
||||||
|
define('DEBUGMODE_ENABLED', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_XMLWriter
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_XMLWriter extends XMLWriter {
|
||||||
|
/** Temporary storage method */
|
||||||
|
const STORAGE_MEMORY = 1;
|
||||||
|
const STORAGE_DISK = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary filename
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $_tempFileName = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new PHPExcel_Shared_XMLWriter instance
|
||||||
|
*
|
||||||
|
* @param int $pTemporaryStorage Temporary storage location
|
||||||
|
* @param string $pTemporaryStorageFolder Temporary storage folder
|
||||||
|
*/
|
||||||
|
public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = NULL) {
|
||||||
|
// Open temporary storage
|
||||||
|
if ($pTemporaryStorage == self::STORAGE_MEMORY) {
|
||||||
|
$this->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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared_ZipArchive
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('PCLZIP_TEMPORARY_DIR')) {
|
||||||
|
define('PCLZIP_TEMPORARY_DIR', PHPExcel_Shared_File::sys_get_temp_dir() . DIRECTORY_SEPARATOR);
|
||||||
|
}
|
||||||
|
require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/PCLZip/pclzip.lib.php';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_ZipArchive
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared_ZipArchive
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_ZipArchive
|
||||||
|
{
|
||||||
|
|
||||||
|
/** constants */
|
||||||
|
const OVERWRITE = 'OVERWRITE';
|
||||||
|
const CREATE = 'CREATE';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary storage directory
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $_tempDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip Archive Stream Handle
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $_zip;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new zip archive
|
||||||
|
*
|
||||||
|
* @param string $fileName Filename for the zip archive
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function open($fileName)
|
||||||
|
{
|
||||||
|
$this->_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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPExcel
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 - 2014 PHPExcel
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
|
||||||
|
* @version ##VERSION##, ##DATE##
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPExcel_Shared_ZipStreamWrapper
|
||||||
|
*
|
||||||
|
* @category PHPExcel
|
||||||
|
* @package PHPExcel_Shared
|
||||||
|
* @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
|
||||||
|
*/
|
||||||
|
class PHPExcel_Shared_ZipStreamWrapper {
|
||||||
|
/**
|
||||||
|
* Internal ZipAcrhive
|
||||||
|
*
|
||||||
|
* @var ZipAcrhive
|
||||||
|
*/
|
||||||
|
private $_archive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filename in ZipAcrhive
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $_fileNameInArchive = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position in file
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $_position = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data
|
||||||
|
*
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
private $_data = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register wrapper
|
||||||
|
*/
|
||||||
|
public static function register() {
|
||||||
|
@stream_wrapper_unregister("zip");
|
||||||
|
@stream_wrapper_register("zip", __CLASS__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements support for fopen().
|
||||||
|
*
|
||||||
|
* @param string $path resource name including scheme, e.g.
|
||||||
|
* @param string $mode only "r" is supported
|
||||||
|
* @param int $options mask of STREAM_REPORT_ERRORS and STREAM_USE_PATH
|
||||||
|
* @param string &$openedPath absolute path of the opened stream (out parameter)
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function stream_open($path, $mode, $options, &$opened_path) {
|
||||||
|
// Check for mode
|
||||||
|
if ($mode{0} != 'r') {
|
||||||
|
throw new PHPExcel_Reader_Exception('Mode ' . $mode . ' is not supported. Only read mode is supported.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = strrpos($path, '#');
|
||||||
|
$url['host'] = substr($path, 6, $pos - 6); // 6: strlen('zip://')
|
||||||
|
$url['fragment'] = substr($path, $pos + 1);
|
||||||
|
|
||||||
|
// Open archive
|
||||||
|
$this->_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue