📄 excelparser.php
字号:
$this->dbglog->debug("Parsed BIFF version is 7");
$biff_ver = 7;
break;
}
}
break;
case 0x0600:
/*DBG*/ $this->dbglog->debug("Parsed BIFF version is 8");
$biff_ver = 8;
break;
default:
return 8;
}
}
if( $biff_ver < 5 ) {
/*DBG*/ $this->dbglog->debug("parse_worksheet() function found ($biff_ver < 5) return 8");
return 8;
}
$ptr = 0;
$data = array('biff_version' => $biff_ver );
while( (ord($ws[$ptr])!=0x0a) && ($ptr<strlen($ws)) ) {
switch (ord($ws[$ptr])+256*ord($ws[$ptr+1])) {
// Formula
// Number
case 0x0203:
case 0x0006:
case 0x0206:
case 0x0406:
/*DBG*/ $this->dbglog->trace("found NUMBER");
if( ($biff_ver < 3) ){
/*DBG*/ $this->dbglog->trace("$biff_ver < 3 break;");
break;
}
if( (ord($ws[$ptr+2])+256*ord($ws[$ptr+3])) < 14 ){
/*DBG*/ $this->dbglog->debug("parse_worksheet() return 6");
return 6;
}
$row = ord($ws[$ptr+4])+256*ord($ws[$ptr+5]);
$col = ord($ws[$ptr+6])+256*ord($ws[$ptr+7]);
$num_lo = str2long(substr($ws,$ptr+10,4));
$num_hi = str2long(substr($ws,$ptr+14,4));
$xf_i = ord($ws[$ptr+8])+256*ord($ws[$ptr+9]);
$data['cell'][$row][$col]['format']=$this->format[$this->xf['format'][$xf_i]];
if($this->isDateFormat($xf_i)){
$data['cell'][$row][$col]['type'] = 3;
} else {
$data['cell'][$row][$col]['type'] = 2;
}
$fonti = $this->xf['font'][$xf_i];
$data['cell'][$row][$fc+$i]['font'] = $fonti;
$fexp = (($num_hi & 0x7ff00000) >> 20) - 1023;
$val = 1+(($num_hi & 0x000fffff) + $num_lo/4294967296)/1048576;
if( $fexp > 0 ) {
for( $i=0; $i<$fexp; $i++ )
$val *= 2;
} else {
for( $i=0; $i<abs($fexp); $i++ )
$val /= 2;
}
if( $num_hi >> 31 ) {
$val = -($val) ;
}
$data['cell'][$row][$col]['data'] = (float)$val;
if( !isset($data['max_row']) ||
($data['max_row'] < $row) )
$data['max_row'] = $row;
if( !isset($data['max_col']) ||
($data['max_col'] < $col) )
$data['max_col'] = $col;
break;
// RK
case 0x027e:
/*DBG*/ $this->dbglog->trace("found RK");
if( ($biff_ver < 3) ) break;
if( (ord($ws[$ptr+2])+256*ord($ws[$ptr+3])) < 0x0a )
return 6;
$row = ord($ws[$ptr+4])+256*ord($ws[$ptr+5]);
$col = ord($ws[$ptr+6])+256*ord($ws[$ptr+7]);
$xf_i = ord($ws[$ptr+8])+256*ord($ws[$ptr+9]);
$val = $this->rk_decode(
str2long(substr($ws,$ptr+10,4))
);
if($this->isDateFormat($xf_i)==TRUE){
$data['cell'][$row][$col]['type'] = 3;
} else {
$data['cell'][$row][$col]['type'] = $val['type'];
}
$fonti = $this->xf['font'][$xf_i];
$data['cell'][$row][$col]['font'] = $fonti;
$data['cell'][$row][$col]['data'] = $val['val'];
$data['cell'][$row][$col]['format']=$this->format[$this->xf['format'][$xf_i]];
if( !isset($data['max_row']) ||
($data['max_row'] < $row) )
$data['max_row'] = $row;
if( !isset($data['max_col']) ||
($data['max_col'] < $col) )
$data['max_col'] = $col;
break;
// MULRK
case 0x00bd:
/*DBG*/ $this->dbglog->trace("found MULL RK");
if( ($biff_ver < 5) ) break;
$sz = ord($ws[$ptr+2])+256*ord($ws[$ptr+3]);
if( $sz < 6 ) return 6;
$row = ord($ws[$ptr+4])+256*ord($ws[$ptr+5]);
$fc = ord($ws[$ptr+6])+256*ord($ws[$ptr+7]);
$lc = ord($ws[$ptr+$sz+2])+256*ord($ws[$ptr+$sz+3]);
for( $i=0; $i<=$lc-$fc; $i++) {
$val = $this->rk_decode(
str2long(substr($ws,$ptr+10+$i*6,4))
);
$xf_i=ord($ws[$ptr+8+$i*6])+256*ord($ws[($ptr+9+$i*6)]);
if($this->isDateFormat($xf_i)==TRUE) {
$data['cell'][$row][$fc+$i]['type'] = 3;
} else {
$data['cell'][$row][$fc+$i]['type'] = $val['type'];
}
$fonti = $this->xf['font'][$xf_i];
$data['cell'][$row][$fc+$i]['font'] = $fonti;
$data['cell'][$row][$fc+$i]['data'] = $val['val'];
$data['cell'][$row][$fc+$i]['format']=$this->format[$this->xf['format'][$xf_i]];
}
if( !isset($data['max_row']) ||
($data['max_row'] < $row) )
$data['max_row'] = $row;
if( !isset($data['max_col']) ||
($data['max_col'] < $lc) )
$data['max_col'] = $lc;
break;
// LABEL
case 0x0204:
/*DBG*/ $this->dbglog->trace("found LABEL");
if( ($biff_ver < 3) ){
break;
}
if( (ord($ws[$ptr+2])+256*ord($ws[$ptr+3])) < 8 ){
return 6;
}
$row = ord($ws[$ptr+4])+256*ord($ws[$ptr+5]);
$col = ord($ws[$ptr+6])+256*ord($ws[$ptr+7]);
$xf = ord($ws[$ptr+8])+256*ord($ws[$ptr+9]);
$fonti = $this->xf['font'][$xf];
$font = $this->fonts[$fonti];
$str_len = ord($ws[$ptr+10])+256*ord($ws[$ptr+11]);
if( $ptr+12+$str_len > strlen($ws) )
return 6;
$this->sst['unicode'][] = false;
$this->sst['data'][] = substr($ws,$ptr+12,$str_len);
$data['cell'][$row][$col]['type'] = 0;
$sst_ind = count($this->sst['data'])-1;
$data['cell'][$row][$col]['data'] = $sst_ind;
$data['cell'][$row][$col]['font'] = $fonti;
/* echo str_replace("\n","<br>\n", ExcelFont::toString($font,$fonti));
echo "FontRecord for sting ".$this->sst['data'][$sst_ind]."<br>";*/
if( !isset($data['max_row']) ||
($data['max_row'] < $row) )
$data['max_row'] = $row;
if( !isset($data['max_col']) ||
($data['max_col'] < $col) )
$data['max_col'] = $col;
break;
// LABELSST
case 0x00fd:
if( $biff_ver < 8 ) break;
if( (ord($ws[$ptr+2])+256*ord($ws[$ptr+3])) < 0x0a )
return 6;
$row = ord($ws[$ptr+4])+256*ord($ws[$ptr+5]);
$col = ord($ws[$ptr+6])+256*ord($ws[$ptr+7]);
$xf = ord($ws[$ptr+8])+256*ord($ws[$ptr+9]);
$fonti = $this->xf['font'][$xf];
$font = &$this->fonts[$fonti];
$data['cell'][$row][$col]['type'] = 0;
$sst_ind = str2long(substr($ws,$ptr+10,4));
$data['cell'][$row][$col]['data'] = $sst_ind;
$data['cell'][$row][$col]['font'] = $fonti;
/* echo "FontRecord for sting at $row,$col<br>";
echo str_replace("\n","<br>\n", ExcelFont::toString($font,$fonti));*/
if( !isset($data['max_row']) ||
($data['max_row'] < $row) )
$data['max_row'] = $row;
if( !isset($data['max_col']) ||
($data['max_col'] < $col) )
$data['max_col'] = $col;
break;
// unknown, unsupported or unused opcode
default:
break;
}
$ptr += 4+256*ord($ws[$ptr+3])+ord($ws[$ptr+2]);
}
//$this->dbglog->debug("parse_worksheet() function returns ".var_export($data,true));
if(is_array($data['cell'])&&$_format_needed)
foreach($data['cell'] as $row=>$_value)
if(is_array($_value))
foreach($_value as $col=>$_value)
{
if($_value['format']!='')
{
$_format=$_value['format'];
$format_type='';
if($_format=='General')
{
$format_type='general';
if(is_infinite($_value['data']))
$_value['data']='';
}
preg_match_all('/(0+)((\.(0+))?)(%?)/is', $_format, $matches);
if(is_array($matches[1])&&count($matches[1])>0&&is_array($matches[2])&&count($matches[2])>0)
//Percentage formatting
{
$format_type='numeric';
$_value['data']*=$matches[5][0]=='%'?100:1;
$format_str="%.".strlen($matches[4][0])."f".str_replace('%', '%%', $matches[5][0]);
}
if($format_type=='')
{
preg_match_all('/([^\\\ :\/;@\[\]\$]+)(\\\.{1,1}|:|\/|;|@|\[|\]|\$)?/is', $_format, $matches);
if(is_array($matches)&&is_array($matches[1]))
{
//Date/Time formatting
$format_type='datetime';
$format_str='';
foreach($matches[1] as $key=>$value)
{
$_format_char='';
switch($value)
{
case 'd':
$_format_char='j';
break;
case 'dd':
$_format_char='d';
break;
case 'ddd':
$_format_char='D';
break;
case 'dddd':
$_format_char='d';
break;
case 'm':
$_format_char=$matches[2][$key]==':'?'i':'n';
break;
case 'mm':
$_format_char=(($matches[2][$key-1]==':'||$matches[2][$key-1]==';'||$matches[2][$key]==':'||$matches[2][$key]==';')?'i':'m');
break;
case 'mmm':
$_format_char='M';
break;
case 'mmmm':
$_format_char='F';
break;
case 'mmmmm':
$_format_char='F';
break;
case 'y':
$_format_char='y';
break;
case 'yy':
$_format_char='y';
break;
case 'yyy':
$_format_char='Y';
break;
case 'yyyy':
$_format_char='Y';
break;
case 'h':
$_format_char='G';
break;
case 'hh':
$_format_char='H';
break;
case 's':
$_format_char='s';
break;
case 'ss':
$_format_char='s';
break;
}
if($_format_char!='')
{
$end=stripslashes($matches[2][$key]);
$end=$end==']'?':':$end;
$end=$end=='/'?'.':$end;
$format_str.=$_format_char.($end!=';'?$end:'');
}
}
}
}
switch($format_type)
{
/**
* Warning:
* Negative timestamps are not supported under any known version of Windows.
* Therefore the range of valid years includes only 1970 through 2038.
*/
case 'datetime':
$_data=str_replace(',', '.', $_value['data']);
$date=floor($_data);
$time=60*60*24*("0.".substr($_data, strlen($date)+1));
if($date==0) {
$_mk=gmmktime(0, 0, ceil($time));//, 1, 1, 1970);
} else {
$_mk=gmmktime(0, 0, ceil($time), 1, $date-25568,1970);
}
$res=gmdate($format_str, $_mk);
break;
case 'numeric':
$res=sprintf($format_str, $_value['data']);
break;
case 'general':
$res=$_value['data'];
break;
}
$data['cell'][$row][$col]['data']=$res;//."(".$_value['data'].", $format_str)";
}
}
return $data;
}
/**
* Parse workbook
*/
function parse_workbook( $f_header, $dp )
{
/*DBG*/ $this->dbglog->debug("parse_workbook() function");
$root_entry_block = $f_header->getLong(0x30);
$num_fat_blocks = $f_header->getLong(0x2c);
/*TRC*/ $this->dbglog->trace("Header parsed");
$this->fat = array();
$num_fat_blocks1 = $num_fat_blocks>108? 109: $num_fat_blocks;
$pos = 0x4c;
for( $i = 0; $i < $num_fat_blocks1; $i++ ){
/*TRC*/ $this->dbglog->trace("FOR LOOP iteration i =".$i. " of " .$num_fat_blocks);
$fat_block = $f_header->getLong($pos);
$fatbuf = $dp->get( $fat_block * 0x200, 0x200 );
$fat = new DataProvider( $fatbuf, DP_STRING_SOURCE );
if( $fat->getSize() < 0x200 ){
/*DBG*/ $this->dbglog->debug("parse_workbook() function found (strlen($fat) < 0x200) returns 6");
return 6;
}
for( $j=0; $j<0x80; $j++ )
$this->fat[] = $fat->getLong( $j * 4 );
$fat->close();
unset( $fat_block, $fatbuf, $fat );
$pos += 4;
}
// read XBAT
$pos = ($f_header->getLong(XBAT_START)) * 512;
$blockstart = 109;
for ($j=0;$j<$f_header->getLong(XBAT_COUNT);$j++) {
$nblocks = min($f_header->getLong(BAT_COUNT) - $blockstart, 127);
for ($i=$blockstart;$i<$nblocks+ $blockstart;$i++) {
/*TRC*/ $this->dbglog->trace("FOR LOOP iteration (XBAT) i =".$i. " of " .$num_fat_blocks);
$fat_block = $dp->getLong($pos);
$fatbuf = $dp->get( $fat_block * 0x200, 0x200 );
$fat = new DataProvider( $fatbuf, DP_STRING_SOURCE );
if( $fat->getSize() < 0x200 ){
/*DBG*/ $this->dbglog->debug("parse_workbook() function found (strlen($fat) < 0x200) returns 6");
return 6;
}
for( $j=0; $j<0x80; $j++ )
$this->fat[] = $fat->getLong( $j * 4 );
$fat->close();
unset( $fat_block, $fatbuf, $fat );
$pos += 4;
}
$blockstart += $nblocks;
if ($blockstart < $f_header->getLong(BAT_COUNT)) {
// $pos = getlong($pos);
}
}
/*DBG*/ $this->dbglog->dump( $this->fat, "\$fat" );
if( count($this->fat) < $num_fat_blocks ) {
/*DBG*/ $this->dbglog->debug("parse_workbook() function found (count($this->fat) < $num_fat_blocks) returns 6");
return 6;
}
$chain = $this->get_blocks_chain($root_entry_block);
$dir = new DataProvider( $dp->ReadFromFat( $chain ), DP_STRING_SOURCE );
unset( $chain );
$this->sfat = array();
$small_block = $f_header->getLong( 0x3c );
if( $small_block != 0xfeffffff ) {
$root_entry_index = $this->find_stream( $dir, 'Root Entry');
// Deleted for support MAC files
//if( $root_entry_index < 0 ) {
/*DBG*/ //$this->dbglog->debug("parse_workbook() function dont found Root Entry returns 6");
//return 6;
//}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -