<?php
+
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
-// available at http://getid3.sourceforge.net //
-// or http://www.getid3.org //
-// also https://github.com/JamesHeinrich/getID3 //
-/////////////////////////////////////////////////////////////////
-// See readme.txt for more details //
+// available at https://github.com/JamesHeinrich/getID3 //
+// or https://www.getid3.org //
+// or http://getid3.sourceforge.net //
+// see readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.archive.zip.php //
// ///
/////////////////////////////////////////////////////////////////
+if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
+ exit;
+}
class getid3_zip extends getid3_handler
{
-
+ /**
+ * @return bool
+ */
public function Analyze() {
$info = &$this->getid3->info;
$this->fseek($info['zip']['end_central_directory']['directory_offset']);
$info['zip']['entries_count'] = 0;
- while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
+ while ($centraldirectoryentry = $this->ZIPparseCentralDirectory()) {
$info['zip']['central_directory'][] = $centraldirectoryentry;
$info['zip']['entries_count']++;
$info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
}
}
+ // check for EPUB files
+ if (!empty($info['zip']['entries'][0]['filename']) &&
+ ($info['zip']['entries'][0]['filename'] == 'mimetype') &&
+ ($info['zip']['entries'][0]['compression_method'] == 'store') &&
+ ($info['zip']['entries'][0]['uncompressed_size'] == 20) &&
+ isset($info['zip']['entries'][0]['data_offset'])) {
+ // http://idpf.org/epub/30/spec/epub30-ocf.html
+ // "3.3 OCF ZIP Container Media Type Identification
+ // OCF ZIP Containers must include a mimetype file as the first file in the Container, and the contents of this file must be the MIME type string application/epub+zip.
+ // The contents of the mimetype file must not contain any leading padding or whitespace, must not begin with the Unicode signature (or Byte Order Mark),
+ // and the case of the MIME type string must be exactly as presented above. The mimetype file additionally must be neither compressed nor encrypted,
+ // and there must not be an extra field in its ZIP header."
+ $this->fseek($info['zip']['entries'][0]['data_offset']);
+ if ($this->fread(20) == 'application/epub+zip') {
+ $info['fileformat'] = 'zip.epub';
+ $info['mime_type'] = 'application/epub+zip';
+ }
+ }
+
+ // check for Office Open XML files (e.g. .docx, .xlsx)
if (!empty($info['zip']['files']['[Content_Types].xml']) &&
!empty($info['zip']['files']['_rels']['.rels']) &&
!empty($info['zip']['files']['docProps']['app.xml']) &&
!empty($info['zip']['files']['docProps']['core.xml'])) {
- // http://technet.microsoft.com/en-us/library/cc179224.aspx
- $info['fileformat'] = 'zip.msoffice';
- if (!empty($ThisFileInfo['zip']['files']['ppt'])) {
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
- } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) {
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
- } elseif (!empty($ThisFileInfo['zip']['files']['word'])) {
- $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
- }
+ // http://technet.microsoft.com/en-us/library/cc179224.aspx
+ $info['fileformat'] = 'zip.msoffice';
+ if (!empty($ThisFileInfo['zip']['files']['ppt'])) {
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
+ } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) {
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+ } elseif (!empty($ThisFileInfo['zip']['files']['word'])) {
+ $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+ }
}
return true;
return true;
}
-
+ /**
+ * @return bool
+ */
public function getZIPHeaderFilepointerTopDown() {
$info = &$this->getid3->info;
}
$info['zip']['entries_count'] = 0;
- while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) {
+ while ($centraldirectoryentry = $this->ZIPparseCentralDirectory()) {
$info['zip']['central_directory'][] = $centraldirectoryentry;
$info['zip']['entries_count']++;
$info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size'];
return true;
}
-
+ /**
+ * @return bool
+ */
public function getZIPentriesFilepointer() {
$info = &$this->getid3->info;
return true;
}
-
+ /**
+ * @return array|false
+ */
public function ZIPparseLocalFileHeader() {
$LocalFileHeader['offset'] = $this->ftell();
$DataDescriptor = $this->fread(16);
$LocalFileHeader['data_descriptor']['signature'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4));
if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08"
- $this->getid3->warning[] = 'invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']);
+ $this->getid3->warning('invalid Local File Header Data Descriptor Signature at offset '.($this->ftell() - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']));
$this->fseek($LocalFileHeader['offset']); // seek back to where filepointer originally was so it can be handled properly
return false;
}
return $LocalFileHeader;
}
-
+ /**
+ * @return array|false
+ */
public function ZIPparseCentralDirectory() {
$CentralDirectory['offset'] = $this->ftell();
return $CentralDirectory;
}
+ /**
+ * @return array|false
+ */
public function ZIPparseEndOfCentralDirectory() {
$EndOfCentralDirectory['offset'] = $this->ftell();
return $EndOfCentralDirectory;
}
-
+ /**
+ * @param int $flagbytes
+ * @param int $compressionmethod
+ *
+ * @return array
+ */
public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) {
// https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html
+ $ParsedFlags = array();
$ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001);
// 0x0002 -- see below
// 0x0004 -- see below
return $ParsedFlags;
}
-
+ /**
+ * @param int $index
+ *
+ * @return string
+ */
public static function ZIPversionOSLookup($index) {
static $ZIPversionOSLookup = array(
0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)',
return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]');
}
+ /**
+ * @param int $index
+ *
+ * @return string
+ */
public static function ZIPcompressionMethodLookup($index) {
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html
static $ZIPcompressionMethodLookup = array(
return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]');
}
+ /**
+ * @param int $DOSdate
+ * @param int $DOStime
+ *
+ * @return int
+ */
public static function DOStime2UNIXtime($DOSdate, $DOStime) {
// wFatDate
// Specifies the MS-DOS date. The date is a packed 16-bit value with the following format: