function Add_File_Header($bin, $file, $status, $meth, $volatile = true, $crc = 0, $zlen = 0, $len = 0, $extra = array()) { // Strip leading slashes from file name (fixes bug in windows archive viewer) $file = preg_replace('/^[\\/\\\\]+/', '', $file); if ($bin === false) { $bin = ''; } else { if ($bin === WPONLINEBACKUP_BIN_DATABASE) { $bin = _x('Database', 'Full backup folder name in downloadable ZIP file', 'wponlinebackup') . '/'; if (!$this->bin_database) { $binstatus = array('mod_time' => time()); // Add the Database folder if (true !== $this->Add_File_Header($bin, '', $binstatus, 0x0, false)) { return $ret; } $this->bin_database = true; } } else { if ($bin === WPONLINEBACKUP_BIN_FILESYSTEM) { $bin = _x('FileSystem', 'Full backup folder name in downloadable ZIP file', 'wponlinebackup') . '/'; if (!$this->bin_filesystem) { $binstatus = array('mod_time' => time()); // Add the Database folder if (true !== $this->Add_File_Header($bin, '', $binstatus, 0x0, false)) { return $ret; } $this->bin_filesystem = true; } } } } $file = $bin . $file; // Create dos timestamp $dts = WPOnlineBackup_Functions::DOS_Time($status['mod_time']); // Why don't we use general purpose bit flag bit 3 to make a streamable ZIP file? // So that we can write CRC/ZLEN/LEN after the file data and not need to seek back and rewrite? // Because Mac OS X Archive Utility doesn't work with them :-( // Run this and try it: zip -X - smallfile.txt - | cat > test.zip // Give it lots of data // Then CTRL+D to end STIN and try to extract the test.zip - you'll get an error // Using Windows or unzip command line will work $genpurp = 0x0; // Calculate extra data $extraloc = ''; $extracdr = ''; if (in_array('rjct', $extra)) { // The rejection header we will hide inside an extra field $rjct = $this->disk->Get_Header(); // The extra field $fields = array(array('v', 0x4400), array('v', strlen($rjct))); // Pack extra field and rejection header $extraloc .= WPOnlineBackup_Functions::Pack_Fields($fields) . $rjct; } if ($this->config['backwards_compat']) { // Store the UTF-8 filename in an extra field $fields = array(array('v', 0x7075), array('v', 5 + strlen($file)), array('C', 1), array('V', crc32($file))); $fields = WPOnlineBackup_Functions::Pack_Fields($fields) . $file; $extraloc .= $fields; $extracdr .= $fields; // ASCII filename // We will assume valid UTF-8 was passed in, which currently it should be // It would be a bug if we didn't - UTF8_To_ASCII only works properly with valid UTF-8 since it only modifyes UTF-8 chars $fileloc = WPOnlineBackup_Functions::UTF8_To_ASCII($file); } else { // Just store UTF-8 in the local header, but user gen purpose bit flag 11 $fileloc = $file; $genpurp |= 0x800; } $elenloc = strlen($extraloc); $elencdr = strlen($extracdr); $nlen = strlen($fileloc); // Build file header $fields = array(array('V', 0x4034b50), array('C', 20), array('C', 0), array('v', $genpurp), array('v', $meth), array('V', $dts), array('V', $crc), array('V', $zlen), array('V', $len), array('v', $nlen), array('v', $elenloc)); // Pack fields and calculate "total" length $fields = WPOnlineBackup_Functions::Pack_Fields($fields) . $fileloc . $extraloc; $record_len = strlen($fields) + $zlen; // Write the header and filename if ($volatile) { // Write volatile so we can seek back and modify the CRC/ZLEN/LEN if (true !== ($ret = $this->writer->Start_Volatile())) { return $ret; } if (!is_int($pos = $this->writer->Volatile_Write($fields))) { return $pos; } } else { // No need for pos, we don't need to seek back $pos = false; if (true !== ($ret = $this->writer->Write($fields))) { return $ret; } } // Add to central directory record and increment offset $record = compact('pos', 'fileloc', 'nlen', 'genpurp', 'meth', 'dts', 'crc', 'zlen', 'len', 'elencdr', 'extracdr'); // Store offset of this entry $record['ofs'] = $this->ofs; $this->file_count++; // If we have a CDR already stored, write it to the CDR buffer, creating one if necessary if ($this->last_cdr !== false) { if ($this->cdr === false) { if (($ret = $this->writer->Branch($this->cdr)) !== true) { return $ret; } if (($ret = $this->cdr->Open('cdrbuffer')) !== true) { return $ret; } } if (($ret = $this->Add_CDR_File($this->cdr, $this->last_cdr)) !== true) { return $ret; } } // Store this CDR - if we only end up with a single CDR, we don't bother creating the CDR buffer then $this->last_cdr = $record; // Increase offset to be used for next entry $this->ofs += $record_len; return true; }