/** * Constructor * * @access public * @param integer $time_1st A timestamp * @param integer $time_2nd A timestamp */ function OLE_PPS_Root($time_1st, $time_2nd, $raChild) { $_ole = new OLE(); $_sys = new System(); $this->_tmp_dir = $_sys->tmpdir(); $this->OLE_PPS(null, $_ole->Asc2Ucs('Root Entry'), OLE_PPS_TYPE_ROOT, null, null, null, $time_1st, $time_2nd, null, $raChild); }
/** * Implements support for fopen(). * For creating streams using this wrapper, use OLE_PPS_File::getStream(). * * @param string $path resource name including scheme, e.g. * ole-chainedblockstream://oleInstanceId=1 * @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, &$openedPath) { if ($mode != 'r') { if ($options & STREAM_REPORT_ERRORS) { trigger_error('Only reading is supported', E_USER_WARNING); } return false; } // 25 is length of "ole-chainedblockstream://" parse_str(substr($path, 25), $this->params); if (!isset($this->params['oleInstanceId'], $this->params['blockId'], $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']])) { if ($options & STREAM_REPORT_ERRORS) { trigger_error('OLE stream not found', E_USER_WARNING); } return false; } $this->ole = $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']]; $blockId = $this->params['blockId']; $this->data = ''; if (isset($this->params['size']) && $this->params['size'] < $this->ole->bigBlockThreshold && $blockId != $this->ole->root->_StartBlock) { // Block id refers to small blocks $rootPos = $this->ole->_getBlockOffset($this->ole->root->_StartBlock); while ($blockId != -2) { $pos = $rootPos + $blockId * $this->ole->bigBlockSize; $blockId = $this->ole->sbat[$blockId]; fseek($this->ole->_file_handle, $pos); $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize); } } else { // Block id refers to big blocks while ($blockId != -2) { $pos = $this->ole->_getBlockOffset($blockId); fseek($this->ole->_file_handle, $pos); $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize); $blockId = $this->ole->bbat[$blockId]; } } if (isset($this->params['size'])) { $this->data = substr($this->data, 0, $this->params['size']); } if ($options & STREAM_USE_PATH) { $openedPath = $path; } return true; }
/** * Constructor * * @access public * @param integer $time_1st A timestamp * @param integer $time_2nd A timestamp */ function OLE_PPS_Root($time_1st, $time_2nd, $raChild) { $this->_tmp_dir = ''; $this->OLE_PPS( null, OLE::Asc2Ucs('Root Entry'), OLE_PPS_TYPE_ROOT, null, null, null, $time_1st, $time_2nd, null, $raChild); }
/** * Constructor * * @access public * @param integer $time_1st A timestamp * @param integer $time_2nd A timestamp */ function __construct($time_1st, $time_2nd, $raChild) { $this->_tmp_dir = System::tmpdir(); parent::__construct( null, OLE::Asc2Ucs('Root Entry'), OLE_PPS_TYPE_ROOT, null, null, null, $time_1st, $time_2nd, null, $raChild); }
/** * Store the workbook in an OLE container * * @access private * @return mixed true on success. PEAR_Error on failure */ function _storeOLEFile() { if ($this->_BIFF_version == 0x600) { $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Workbook')); } else { $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Book')); } if ($this->_tmp_dir != '') { $OLE->setTempDir($this->_tmp_dir); } $res = $OLE->init(); if ($this->isError($res)) { return $this->raiseError("OLE Error: " . $res->getMessage()); } $OLE->append($this->_data); $total_worksheets = count($this->_worksheets); for ($i = 0; $i < $total_worksheets; $i++) { while ($tmp = $this->_worksheets[$i]->getData()) { $OLE->append($tmp); } } $root = new OLE_PPS_Root(time(), time(), array($OLE)); if ($this->_tmp_dir != '') { $root->setTempDir($this->_tmp_dir); } $res = $root->save($this->_filename); if ($this->isError($res)) { return $this->raiseError("OLE Error: " . $res->getMessage()); } return true; }
/** * Returns a string with the PPS's WK (What is a WK?) * * @access private * @return string The binary string */ function _getPpsWk() { $ret = $this->Name; for ($i = 0; $i < (64 - strlen($this->Name)); $i++) { $ret .= "\x00"; } $ret .= pack("v", strlen($this->Name) + 2) // 66 . pack("c", $this->Type) // 67 . pack("c", 0x00) //UK // 68 . pack("V", $this->PrevPps) //Prev // 72 . pack("V", $this->NextPps) //Next // 76 . pack("V", $this->DirPps) //Dir // 80 . "\x00\x09\x02\x00" // 84 . "\x00\x00\x00\x00" // 88 . "\xc0\x00\x00\x00" // 92 . "\x00\x00\x00\x46" // 96 // Seems to be ok only for Root . "\x00\x00\x00\x00" // 100 . OLE::LocalDate2OLE($this->Time1st) // 108 . OLE::LocalDate2OLE($this->Time2nd) // 116 . pack("V", isset($this->_StartBlock)? $this->_StartBlock:0) // 120 . pack("V", $this->Size) // 124 . pack("V", 0); // 128 return $ret; }
/** * Gets information about all PPS's on the OLE container from the PPS WK's * creates an OLE_PPS object for each one. * * @access private * @param integer $pps_wk_start Position inside the OLE file where PPS WK's start * @param integer $big_block_size Size of big blobks in the OLE file * @return mixed true on success, PEAR_Error on failure */ function _readPpsWks($pps_wk_start, $big_block_size) { $pointer = ($pps_wk_start + 1) * $big_block_size; while (1) { fseek($this->_file_handle, $pointer); $pps_wk = fread($this->_file_handle, OLE_PPS_SIZE); if (strlen($pps_wk) != OLE_PPS_SIZE) { break; // Excel likes to add a trailing byte sometimes //return $this->raiseError("PPS at $pointer seems too short: ".strlen($pps_wk)); } $name_length = unpack("c", substr($pps_wk, 64, 2)); // FIXME (2 bytes??) $name_length = $name_length[''] - 2; $name = substr($pps_wk, 0, $name_length); $type = unpack("c", substr($pps_wk, 66, 1)); if (($type[''] != OLE_PPS_TYPE_ROOT) and ($type[''] != OLE_PPS_TYPE_DIR) and ($type[''] != OLE_PPS_TYPE_FILE)) { return $this->raiseError("PPS at $pointer has unknown type: {$type['']}"); } $prev = unpack("V", substr($pps_wk, 68, 4)); $next = unpack("V", substr($pps_wk, 72, 4)); $dir = unpack("V", substr($pps_wk, 76, 4)); // there is no magic number, it can take different values. //$magic = unpack("V", strrev(substr($pps_wk, 92, 4))); $time_1st = substr($pps_wk, 100, 8); $time_2nd = substr($pps_wk, 108, 8); $start_block = unpack("V", substr($pps_wk, 116, 4)); $size = unpack("V", substr($pps_wk, 120, 4)); // _data member will point to position in file!! // OLE_PPS object is created with an empty children array!! $this->_list[] = new OLE_PPS(null, '', $type[''], $prev[''], $next[''], $dir[''], OLE::OLE2LocalDate($time_1st), OLE::OLE2LocalDate($time_2nd), ($start_block[''] + 1) * $big_block_size, array()); // give it a size $this->_list[count($this->_list) - 1]->Size = $size['']; // check if the PPS tree (starting from root) is complete if ($this->_ppsTreeComplete(0)) { break; } $pointer += OLE_PPS_SIZE; } }
/** * Returns a string with the PPS's WK (What is a WK?) * * @access private * @return string The binary string */ function _getPpsWk() { $ret = $this->Name; for ($i = 0; $i < 64 - strlen($this->Name); $i++) { $ret .= ""; } $ret .= pack("v", strlen($this->Name) + 2) . pack("c", $this->Type) . pack("c", 0x0) . pack("V", $this->PrevPps) . pack("V", $this->NextPps) . pack("V", $this->DirPps) . "\t" . "" . "À" . "F" . "" . OLE::LocalDate2OLE($this->Time1st) . OLE::LocalDate2OLE($this->Time2nd) . pack("V", isset($this->_StartBlock) ? $this->_StartBlock : 0) . pack("V", $this->Size) . pack("V", 0); // 128 return $ret; }
/** * Gets information about all PPS's on the OLE container from the PPS WK's * creates an OLE_PPS object for each one. * * @access private * @param integer $blockId the block id of the first block * @return mixed true on success, PEAR_Error on failure */ function _readPpsWks($blockId) { global $FANNIE_ROOT; $fh = $this->getStream($blockId); for ($pos = 0;; $pos += 128) { fseek($fh, $pos, SEEK_SET); $nameUtf16 = fread($fh, 64); $nameLength = $this->_readInt2($fh); $nameUtf16 = substr($nameUtf16, 0, $nameLength - 2); // Simple conversion from UTF-16LE to ISO-8859-1 $name = str_replace("", "", $nameUtf16); $type = $this->_readInt1($fh); switch ($type) { case OLE_PPS_TYPE_ROOT: require_once dirname(__FILE__) . '/PPS/Root.php'; $pps = new OLE_PPS_Root(null, null, array()); $this->root = $pps; break; case OLE_PPS_TYPE_DIR: $pps = new OLE_PPS(null, null, null, null, null, null, null, null, null, array()); break; case OLE_PPS_TYPE_FILE: require_once dirname(__FILE__) . '/PPS/File.php'; $pps = new OLE_PPS_File($name); break; default: continue; } fseek($fh, 1, SEEK_CUR); $pps->Type = $type; $pps->Name = $name; $pps->PrevPps = $this->_readInt4($fh); $pps->NextPps = $this->_readInt4($fh); $pps->DirPps = $this->_readInt4($fh); fseek($fh, 20, SEEK_CUR); $pps->Time1st = OLE::OLE2LocalDate(fread($fh, 8)); $pps->Time2nd = OLE::OLE2LocalDate(fread($fh, 8)); $pps->_StartBlock = $this->_readInt4($fh); $pps->Size = $this->_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 == OLE_PPS_TYPE_DIR || $pps->Type == 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; }
/** * Store the workbook in an OLE container * * @access private * @return mixed true on success. PEAR_Error on failure */ protected function storeOLEFile() { if ($this->BIFF_version == 0x600) { $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Workbook')); } else { $OLE = new OLE_PPS_File(OLE::Asc2Ucs('Book')); } if ($this->temporaryDirectory != '') { $OLE->setTempDir($this->temporaryDirectory); } $res = $OLE->init(); if ($this->isError($res)) { return $this->raiseError('OLE Error: ' . $res->getMessage()); } $OLE->append($this->data); $total_worksheets = count($this->workSheet); for ($i = 0; $i < $total_worksheets; ++$i) { while ($tmp = $this->workSheet[$i]->getData()) { $OLE->append($tmp); } } $root = new OLE_PPS_Root(time(), time(), array($OLE)); if ($this->temporaryDirectory != '') { $root->setTempDir($this->temporaryDirectory); } $res = $root->save($this->fileName); if ($this->isError($res)) { return $this->raiseError('OLE Error: ' . $res->getMessage()); } return true; }
/** * The constructor * * @param string $name The name of the file (in Unicode) */ public function __construct($name) { parent::__construct(null, OLE::asc2Ucs($name), self::PPS_TYPE_FILE); }