diff --git a/.gitattributes b/.gitattributes index c2d9ebc4..cb6c6c7f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -31,3 +31,4 @@ Doxyfile export-ignore /phpstan.neon export-ignore /phpunit.xml.dist export-ignore /tests export-ignore +/demos export-ignore diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5ce8e3c4..89ccce9f 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -6,6 +6,7 @@ jobs: lint: name: "Lint" runs-on: "ubuntu-latest" + continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: @@ -22,14 +23,22 @@ jobs: - "8.1" - "8.2" - "8.3" + experimental: + - false + include: + - php-version: "8.4" + experimental: true + composer-options: "--ignore-platform-reqs" steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" ini-values: error_reporting=-1, display_errors=On coverage: "none" - uses: "ramsey/composer-install@v2" + with: + composer-options: "${{ matrix.composer-options }}" - name: "Run the linter" run: "composer lint -- --colors" @@ -37,11 +46,11 @@ jobs: name: "Static Analysis" runs-on: "ubuntu-latest" steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - uses: "shivammathur/setup-php@v2" with: - php-version: "7.4" - tools: "phpstan:1.8.11" + php-version: "8.2" + tools: "phpstan:1.10.57" coverage: "none" - uses: "ramsey/composer-install@v2" - name: "Run PHPStan" @@ -66,14 +75,15 @@ jobs: - "8.0" - "8.1" - "8.2" + - "8.3" experimental: - false include: - - php-version: "8.3" + - php-version: "8.4" experimental: true composer-options: "--ignore-platform-reqs" steps: - - uses: "actions/checkout@v3" + - uses: "actions/checkout@v4" - uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" diff --git a/src/Cache/Dbm.php b/src/Cache/Dbm.php index c84598a8..4a43fe12 100644 --- a/src/Cache/Dbm.php +++ b/src/Cache/Dbm.php @@ -245,7 +245,7 @@ public function analyze($filename, $filesize=null, $original_filename='', $fp=nu $result = parent::analyze($filename, $filesize, $original_filename, $fp); // Save result - if (isset($key) && file_exists($filename)) { + if ($key !== null) { dba_insert($key, serialize($result), $this->dba); } diff --git a/src/GetID3.php b/src/GetID3.php index 13b0ddef..3925d1de 100644 --- a/src/GetID3.php +++ b/src/GetID3.php @@ -319,7 +319,7 @@ class GetID3 */ protected $startup_warning = ''; - const VERSION = '2.0.x-202310190849'; + const VERSION = '2.0.x-202405201327'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; @@ -341,10 +341,10 @@ public function __construct() { $memoryLimit = ini_get('memory_limit'); if (preg_match('#([0-9]+) ?M#i', $memoryLimit, $matches)) { // could be stored as "16M" rather than 16777216 for example - $memoryLimit = $matches[1] * 1048576; + $memoryLimit = (int) $matches[1] * 1048576; } elseif (preg_match('#([0-9]+) ?G#i', $memoryLimit, $matches)) { // The 'G' modifier is available since PHP 5.1.0 // could be stored as "2G" rather than 2147483648 for example - $memoryLimit = $matches[1] * 1073741824; + $memoryLimit = (int) $matches[1] * 1073741824; } $this->memory_limit = $memoryLimit; @@ -1265,6 +1265,15 @@ public function GetFileFormatArray() { // Misc other formats + // GPX - data - GPS Exchange Format + 'gpx' => array ( + 'pattern' => '^<\\?xml [^>]+>[\s]* 'Misc\\Gpx', + 'mime_type' => 'application/gpx+xml', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + // PAR2 - data - Parity Volume Set Specification 2.0 'par2' => array ( 'pattern' => '^PAR2\\x00PKT', diff --git a/src/Module/Audio/Dss.php b/src/Module/Audio/Dss.php index 30be4f37..1d5ad9ef 100644 --- a/src/Module/Audio/Dss.php +++ b/src/Module/Audio/Dss.php @@ -83,11 +83,11 @@ public function Analyze() { */ public function DSSdateStringToUnixDate($datestring) { $y = (int) substr($datestring, 0, 2); - $m = substr($datestring, 2, 2); - $d = substr($datestring, 4, 2); - $h = substr($datestring, 6, 2); - $i = substr($datestring, 8, 2); - $s = substr($datestring, 10, 2); + $m = (int) substr($datestring, 2, 2); + $d = (int) substr($datestring, 4, 2); + $h = (int) substr($datestring, 6, 2); + $i = (int) substr($datestring, 8, 2); + $s = (int) substr($datestring, 10, 2); $y += (($y < 95) ? 2000 : 1900); return mktime($h, $i, $s, $m, $d, $y); } diff --git a/src/Module/Audio/Midi.php b/src/Module/Audio/Midi.php index aeb85afa..bc7b2078 100644 --- a/src/Module/Audio/Midi.php +++ b/src/Module/Audio/Midi.php @@ -118,7 +118,7 @@ public function Analyze() { $TicksAtCurrentBPM = 0; while ($eventsoffset < strlen($trackdata)) { $eventid = 0; - if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) { + if (isset($MIDIevents[$tracknumber])) { $eventid = count($MIDIevents[$tracknumber]); } $deltatime = 0; diff --git a/src/Module/AudioVideo/Asf.php b/src/Module/AudioVideo/Asf.php index de6f4572..f2fe80d3 100644 --- a/src/Module/AudioVideo/Asf.php +++ b/src/Module/AudioVideo/Asf.php @@ -501,13 +501,17 @@ public function Analyze() { $offset += 2; $thisfile_asf_scriptcommandobject['command_types_count'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) { - $CommandTypeNameLength = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character - $offset += 2; - $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); - $offset += $CommandTypeNameLength; + if ($thisfile_asf_scriptcommandobject['command_types_count'] > 0) { + $thisfile_asf_scriptcommandobject['command_types'] = array(); + for ($CommandTypesCounter = 0; $CommandTypesCounter < (int) $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) { + $CommandTypeNameLength = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter] = array(); + $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); + $offset += $CommandTypeNameLength; + } } - for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) { + for ($CommandsCounter = 0; $CommandsCounter < (int) $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) { $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); $offset += 4; $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); @@ -556,6 +560,8 @@ public function Analyze() { break; } $thisfile_asf_markerobject['markers_count'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + /** @var int|float|false $totalMakersCount */ + $totalMakersCount = $thisfile_asf_markerobject['markers_count']; $offset += 4; $thisfile_asf_markerobject['reserved_2'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; @@ -567,7 +573,8 @@ public function Analyze() { $offset += 2; $thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']); $offset += $thisfile_asf_markerobject['name_length']; - for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) { + for ($MarkersCounter = 0; $MarkersCounter < $totalMakersCount; $MarkersCounter++) { + $thisfile_asf_markerobject['markers'][$MarkersCounter] = array(); $thisfile_asf_markerobject['markers'][$MarkersCounter]['offset'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); $offset += 8; $thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); @@ -617,7 +624,7 @@ public function Analyze() { } $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) { + for ($StreamNumberCounter = 0; $StreamNumberCounter < (int) $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) { $thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; } @@ -761,7 +768,7 @@ public function Analyze() { $thisfile_asf_extendedcontentdescriptionobject['objectsize'] = $NextObjectSize; $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { + for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < (int) $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { // shortcut $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array(); $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter]; @@ -957,7 +964,8 @@ public function Analyze() { $thisfile_asf_streambitratepropertiesobject['objectsize'] = $NextObjectSize; $thisfile_asf_streambitratepropertiesobject['bitrate_records_count'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; - for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < (int) $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { + $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter] = array(); $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = Utils::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); $offset += 2; $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F; @@ -1006,7 +1014,7 @@ public function Analyze() { if (isset($thisfile_asf_streambitratepropertiesobject['bitrate_records_count'])) { $ASFbitrateAudio = 0; $ASFbitrateVideo = 0; - for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < (int) $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { case 1: @@ -1030,7 +1038,7 @@ public function Analyze() { $thisfile_video['bitrate'] = $ASFbitrateVideo; } } - if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) { + if (isset($thisfile_asf['stream_properties_object'])) { $thisfile_audio['bitrate'] = 0; $thisfile_video['bitrate'] = 0; @@ -1067,7 +1075,7 @@ public function Analyze() { } if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { // @phpstan-ignore-line - foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { + foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { // @phpstan-ignore-line if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate']; $thisfile_audio['bitrate'] += $dataarray['bitrate']; @@ -1153,7 +1161,7 @@ public function Analyze() { $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { // @phpstan-ignore-line - foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { + foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { // @phpstan-ignore-line if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate']; $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate']; @@ -1266,10 +1274,13 @@ public function Analyze() { $thisfile_asf_simpleindexobject['maximum_packet_count'] = Utils::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); $offset += 4; $thisfile_asf_simpleindexobject['index_entries_count'] = Utils::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); + /** @var int|float|false $totalIndexEntriesCount */ + $totalIndexEntriesCount = $thisfile_asf_simpleindexobject['index_entries_count']; $offset += 4; - $IndexEntriesData = $SimpleIndexObjectData.$this->fread(6 * $thisfile_asf_simpleindexobject['index_entries_count']); - for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) { + $IndexEntriesData = $SimpleIndexObjectData.$this->fread(6 * $totalIndexEntriesCount); + for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $totalIndexEntriesCount; $IndexEntriesCounter++) { + $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter] = array(); $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = Utils::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); $offset += 4; $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count'] = Utils::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); @@ -1320,9 +1331,10 @@ public function Analyze() { $offset += 4; $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count']); - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < (int) $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { $IndexSpecifierStreamNumber = Utils::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); $offset += 2; + $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter] = array(); $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number'] = $IndexSpecifierStreamNumber; $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type'] = Utils::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); $offset += 2; @@ -1331,17 +1343,19 @@ public function Analyze() { $ASFIndexObjectData .= $this->fread(4); $thisfile_asf_asfindexobject['index_entry_count'] = Utils::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + /** @var int|float|false $totalIndexEntryCount */ + $totalIndexEntryCount = $thisfile_asf_asfindexobject['index_entry_count']; $offset += 4; $ASFIndexObjectData .= $this->fread(8 * $thisfile_asf_asfindexobject['index_specifiers_count']); - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < (int) $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { $thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = Utils::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8)); $offset += 8; } $ASFIndexObjectData .= $this->fread(4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']); - for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) { - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + for ($IndexEntryCounter = 0; $IndexEntryCounter < $totalIndexEntryCount; $IndexEntryCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < (int) $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { $thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = Utils::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); $offset += 4; } diff --git a/src/Module/AudioVideo/Mpeg.php b/src/Module/AudioVideo/Mpeg.php index fe24265b..d2ed36e6 100644 --- a/src/Module/AudioVideo/Mpeg.php +++ b/src/Module/AudioVideo/Mpeg.php @@ -292,6 +292,10 @@ public function Analyze() { $GOPheader['time_code'] = sprintf('%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d'.$time_code_separator.'%02d', $GOPheader['time_code_hours'], $GOPheader['time_code_minutes'], $GOPheader['time_code_seconds'], $GOPheader['time_code_pictures']); $info['mpeg']['group_of_pictures'][] = $GOPheader; + } else { + // https://github.com/JamesHeinrich/getID3/issues/440 + $this->warning('group_of_pictures['.$GOPcounter.'] no valid bitratemode'); + $info['mpeg']['group_of_pictures'][] = array(); } break; diff --git a/src/Module/AudioVideo/QuickTime.php b/src/Module/AudioVideo/QuickTime.php index d4742772..0f2bea29 100644 --- a/src/Module/AudioVideo/QuickTime.php +++ b/src/Module/AudioVideo/QuickTime.php @@ -40,12 +40,21 @@ class QuickTime extends Handler */ public $ParseAllPossibleAtoms = false; + /** + * real ugly, but so is the QuickTime structure that stores keys and values in different multi-nested locations that are hard to relate to each other + * https://github.com/JamesHeinrich/getID3/issues/214 + * + * @var int + */ + private $metaDATAkey = 1; + /** * @return bool */ public function Analyze() { $info = &$this->getid3->info; + $this->metaDATAkey = 1; $info['fileformat'] = 'quicktime'; $info['quicktime']['hinting'] = false; $info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present @@ -149,27 +158,27 @@ public function Analyze() { @list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches; if (strlen($lat_deg) == 2) { // [+-]DD.D - $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim($lat_deg, '0').$lat_deg_dec); + $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (float) (ltrim($lat_deg, '0').$lat_deg_dec); } elseif (strlen($lat_deg) == 4) { // [+-]DDMM.M - $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60); + $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (int) ltrim(substr($lat_deg, 0, 2), '0') + ((float) (ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec) / 60); } elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S - $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval((int) ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600); + $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * (int) ltrim(substr($lat_deg, 0, 2), '0') + ((int) ltrim(substr($lat_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec) / 3600); } if (strlen($lon_deg) == 3) { // [+-]DDD.D - $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim($lon_deg, '0').$lon_deg_dec); + $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (float) (ltrim($lon_deg, '0').$lon_deg_dec); } elseif (strlen($lon_deg) == 5) { // [+-]DDDMM.M - $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60); + $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (int) ltrim(substr($lon_deg, 0, 2), '0') + ((float) (ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec) / 60); } elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S - $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval((int) ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600); + $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * (int) ltrim(substr($lon_deg, 0, 2), '0') + ((int) ltrim(substr($lon_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec) / 3600); } if (strlen($alt_deg) == 3) { // [+-]DDD.D - $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim($alt_deg, '0').$alt_deg_dec); + $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (float) (ltrim($alt_deg, '0').$alt_deg_dec); } elseif (strlen($alt_deg) == 5) { // [+-]DDDMM.M - $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60); + $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (int) ltrim(substr($alt_deg, 0, 2), '0') + ((float) (ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec) / 60); } elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S - $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval((int) ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600); + $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * (int) ltrim(substr($alt_deg, 0, 2), '0') + ((int) ltrim(substr($alt_deg, 2, 2), '0') / 60) + ((float) (ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec) / 3600); } foreach (array('latitude', 'longitude', 'altitude') as $key) { @@ -795,7 +804,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset } $stsdEntriesDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + for ($i = 0; $i < (int) $atom_structure['number_entries']; $i++) { $atom_structure['sample_description_table'][$i]['size'] = Utils::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4)); $stsdEntriesDataOffset += 4; $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4); @@ -1720,13 +1729,12 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset break; case 'data': // metaDATA atom - static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data $atom_structure['language'] = substr($atom_data, 4 + 0, 2); $atom_structure['unknown'] = Utils::BigEndian2Int(substr($atom_data, 4 + 2, 2)); $atom_structure['data'] = substr($atom_data, 4 + 4); - $atom_structure['key_name'] = (isset($info['quicktime']['temp_meta_key_names'][$metaDATAkey]) ? $info['quicktime']['temp_meta_key_names'][$metaDATAkey] : ''); - $metaDATAkey++; + $atom_structure['key_name'] = (isset($info['quicktime']['temp_meta_key_names'][$this->metaDATAkey]) ? $info['quicktime']['temp_meta_key_names'][$this->metaDATAkey] : ''); + $this->metaDATAkey++; if ($atom_structure['key_name'] && $atom_structure['data']) { @$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data']; @@ -1970,16 +1978,16 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset foreach (array('latitude','longitude') as $latlon) { preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches); list($dummy, $deg, $min) = $matches; - $GPS_this_GPRMC[$latlon] = $deg + ($min / 60); + $GPS_this_GPRMC[$latlon] = (int) $deg + ((float) $min / 60); } $GPS_this_GPRMC['latitude'] *= (($GPS_this_GPRMC['raw']['latitude_direction'] == 'S') ? -1 : 1); $GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1); $GPS_this_GPRMC['heading'] = $GPS_this_GPRMC['raw']['angle']; $GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots']; - $GPS_this_GPRMC['speed_kmh'] = $GPS_this_GPRMC['raw']['knots'] * 1.852; + $GPS_this_GPRMC['speed_kmh'] = (float) $GPS_this_GPRMC['raw']['knots'] * 1.852; if ($GPS_this_GPRMC['raw']['variation']) { - $GPS_this_GPRMC['variation'] = $GPS_this_GPRMC['raw']['variation']; + $GPS_this_GPRMC['variation'] = (float) $GPS_this_GPRMC['raw']['variation']; $GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1); } @@ -2113,7 +2121,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_DescrTag'] = Utils::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_DescrTag'] != 0x03) { - $this->warning('expecting esds.ES_DescrTag = 0x03, found 0x'.Utils::PrintHexBytes($atom_structure['ES_DescrTag']).'), at offset '.$atom_structure['offset']); + $this->warning('expecting esds.ES_DescrTag = 0x03, found 0x'.sprintf('%02X', $atom_structure['ES_DescrTag']).', at offset '.$atom_structure['offset']); break; } $atom_structure['ES_DescrSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); @@ -2142,7 +2150,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_DecoderConfigDescrTag'] = Utils::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_DecoderConfigDescrTag'] != 0x04) { - $this->warning('expecting esds.ES_DecoderConfigDescrTag = 0x04, found 0x'.Utils::PrintHexBytes($atom_structure['ES_DecoderConfigDescrTag']).'), at offset '.$atom_structure['offset']); + $this->warning('expecting esds.ES_DecoderConfigDescrTag = 0x04, found 0x'.sprintf('%02X', $atom_structure['ES_DecoderConfigDescrTag']).', at offset '.$atom_structure['offset']); break; } $atom_structure['ES_DecoderConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); @@ -2173,7 +2181,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_DecSpecificInfoTag'] = Utils::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_DecSpecificInfoTag'] != 0x05) { - $this->warning('expecting esds.ES_DecSpecificInfoTag = 0x05, found 0x'.Utils::PrintHexBytes($atom_structure['ES_DecSpecificInfoTag']).'), at offset '.$atom_structure['offset']); + $this->warning('expecting esds.ES_DecSpecificInfoTag = 0x05, found 0x'.sprintf('%02X', $atom_structure['ES_DecSpecificInfoTag']).', at offset '.$atom_structure['offset']); break; } $atom_structure['ES_DecSpecificInfoTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); @@ -2184,7 +2192,7 @@ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset $atom_structure['ES_SLConfigDescrTag'] = Utils::BigEndian2Int(substr($atom_data, $esds_offset, 1)); $esds_offset += 1; if ($atom_structure['ES_SLConfigDescrTag'] != 0x06) { - $this->warning('expecting esds.ES_SLConfigDescrTag = 0x05, found 0x'.Utils::PrintHexBytes($atom_structure['ES_SLConfigDescrTag']).'), at offset '.$atom_structure['offset']); + $this->warning('expecting esds.ES_SLConfigDescrTag = 0x05, found 0x'.sprintf('%02X', $atom_structure['ES_SLConfigDescrTag']).', at offset '.$atom_structure['offset']); break; } $atom_structure['ES_SLConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); diff --git a/src/Module/AudioVideo/Riff.php b/src/Module/AudioVideo/Riff.php index 34c7108f..fc2c2a8f 100644 --- a/src/Module/AudioVideo/Riff.php +++ b/src/Module/AudioVideo/Riff.php @@ -305,8 +305,9 @@ public function Analyze() { // assigned for text fields, resulting in a null-terminated string (or possibly just a single null) followed by garbage // Keep only string as far as first null byte, discard rest of fixed-width data // https://github.com/JamesHeinrich/getID3/issues/263 - $null_terminator_offset = strpos($thisfile_riff_WAVE_bext_0[$bext_key], "\x00"); - $thisfile_riff_WAVE_bext_0[$bext_key] = substr($thisfile_riff_WAVE_bext_0[$bext_key], 0, $null_terminator_offset); + // https://github.com/JamesHeinrich/getID3/issues/430 + $null_terminator_rows = explode("\x00", $thisfile_riff_WAVE_bext_0[$bext_key]); + $thisfile_riff_WAVE_bext_0[$bext_key] = $null_terminator_rows[0]; } $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10); @@ -1132,7 +1133,9 @@ public function Analyze() { $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); foreach ($CommentsChunkNames as $key => $value) { if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { - $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; + // https://github.com/JamesHeinrich/getID3/issues/430 + $null_terminator_rows = explode("\x00", $thisfile_riff[$RIFFsubtype][$key][0]['data']); + $thisfile_riff['comments'][$value][] = $null_terminator_rows[0]; } } /* @@ -1223,7 +1226,9 @@ public function Analyze() { $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); foreach ($CommentsChunkNames as $key => $value) { if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { - $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; + // https://github.com/JamesHeinrich/getID3/issues/430 + $null_terminator_rows = explode("\x00", $thisfile_riff[$RIFFsubtype][$key][0]['data']); + $thisfile_riff['comments'][$value][] = $null_terminator_rows[0]; } } @@ -1359,19 +1364,19 @@ public function Analyze() { } if ($info['playtime_seconds'] > 0) { - if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { + if ($thisfile_riff_audio !== null && $thisfile_riff_video !== null) { if (!isset($info['bitrate'])) { $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); } - } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) { + } elseif ($thisfile_riff_audio !== null && $thisfile_riff_video === null) { if (!isset($thisfile_audio['bitrate'])) { $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); } - } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { + } elseif ($thisfile_riff_audio === null && $thisfile_riff_video !== null) { if (!isset($thisfile_video['bitrate'])) { $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); @@ -1688,7 +1693,7 @@ public function ParseRIFF($startoffset, $maxoffset) { break; } $thisindex = 0; - if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) { + if (isset($RIFFchunk[$chunkname])) { $thisindex = count($RIFFchunk[$chunkname]); } $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8; diff --git a/src/Module/Graphic/Png.php b/src/Module/Graphic/Png.php index 103f6a90..7972d202 100644 --- a/src/Module/Graphic/Png.php +++ b/src/Module/Graphic/Png.php @@ -137,7 +137,7 @@ public function Analyze() { case 'tRNS': // Transparency $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { + switch ($thisfile_png['IHDR']['raw']['color_type']) { // @phpstan-ignore-line case 0: $thisfile_png_chunk_type_text['transparent_color_gray'] = Utils::BigEndian2Int(substr($chunk['data'], 0, 2)); break; @@ -160,7 +160,7 @@ public function Analyze() { break; default: - $this->warning('Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']); + $this->warning('Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']); // @phpstan-ignore-line break; } break; @@ -273,7 +273,7 @@ public function Analyze() { case 'bKGD': // Background Color $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { + switch ($thisfile_png['IHDR']['raw']['color_type']) { // @phpstan-ignore-line case 0: case 4: $thisfile_png_chunk_type_text['background_gray'] = Utils::BigEndian2Int($chunk['data']); @@ -307,7 +307,7 @@ public function Analyze() { case 'sBIT': // Significant Bits $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { + switch ($thisfile_png['IHDR']['raw']['color_type']) { // @phpstan-ignore-line case 0: $thisfile_png_chunk_type_text['significant_bits_gray'] = Utils::BigEndian2Int(substr($chunk['data'], 0, 1)); break; @@ -422,10 +422,7 @@ public function Analyze() { case 'gIFg': // GIF Graphic Control Extension - $gIFgCounter = 0; - if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { - $gIFgCounter = count($thisfile_png_chunk_type_text); - } + $gIFgCounter = count($thisfile_png_chunk_type_text); $thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk; $thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = Utils::BigEndian2Int(substr($chunk['data'], 0, 1)); $thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = Utils::BigEndian2Int(substr($chunk['data'], 1, 1)); @@ -434,10 +431,7 @@ public function Analyze() { case 'gIFx': // GIF Application Extension - $gIFxCounter = 0; - if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { - $gIFxCounter = count($thisfile_png_chunk_type_text); - } + $gIFxCounter = count($thisfile_png_chunk_type_text); $thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk; $thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8); $thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3); @@ -446,10 +440,7 @@ public function Analyze() { case 'IDAT': // Image Data - $idatinformationfieldindex = 0; - if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) { - $idatinformationfieldindex = count($thisfile_png['IDAT']); - } + $idatinformationfieldindex = count($thisfile_png['IDAT']); unset($chunk['data']); $thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk; break; diff --git a/src/Module/Misc/Gpx.php b/src/Module/Misc/Gpx.php new file mode 100644 index 00000000..031f0acc --- /dev/null +++ b/src/Module/Misc/Gpx.php @@ -0,0 +1,36 @@ + // +// available at https://github.com/JamesHeinrich/getID3 // +// or https://www.getid3.org // +// or http://getid3.sourceforge.net // +// see readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.gpx.php // +// module for analyzing gpx files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + +class Gpx extends Handler +{ + /** + * @return bool + */ + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'gpx'; + + $this->error('gpx parsing not enabled in this version of getID3()'); + return false; + + } + +} diff --git a/src/Module/Tag/ApeTag.php b/src/Module/Tag/ApeTag.php index 7c339a1f..ba875baa 100644 --- a/src/Module/Tag/ApeTag.php +++ b/src/Module/Tag/ApeTag.php @@ -42,6 +42,10 @@ public function Analyze() { $this->warning('Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'); return false; } + if (PHP_INT_MAX == 2147483647) { + // https://github.com/JamesHeinrich/getID3/issues/439 + $this->warning('APEtag flags may not be parsed correctly on 32-bit PHP'); + } $id3v1tagsize = 128; $apetagheadersize = 32; diff --git a/src/Module/Tag/ID3v2.php b/src/Module/Tag/ID3v2.php index 36306ec1..c09cb87f 100644 --- a/src/Module/Tag/ID3v2.php +++ b/src/Module/Tag/ID3v2.php @@ -1067,13 +1067,15 @@ public function ParseID3v2Frame(&$parsedFrame) { $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset); $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator)); - if (($timestampindex == 0) && (ord($frame_remainingdata[0]) != 0)) { - // timestamp probably omitted for first data item - } else { - $parsedFrame['lyrics'][$timestampindex]['timestamp'] = Utils::BigEndian2Int(substr($frame_remainingdata, 0, 4)); - $frame_remainingdata = substr($frame_remainingdata, 4); + if (strlen($frame_remainingdata)) { // https://github.com/JamesHeinrich/getID3/issues/444 + if (($timestampindex == 0) && (ord($frame_remainingdata[0]) != 0)) { + // timestamp probably omitted for first data item + } else { + $parsedFrame['lyrics'][$timestampindex]['timestamp'] = Utils::BigEndian2Int(substr($frame_remainingdata, 0, 4)); + $frame_remainingdata = substr($frame_remainingdata, 4); + } + $timestampindex++; } - $timestampindex++; } } unset($parsedFrame['data']); @@ -1303,7 +1305,7 @@ public function ParseID3v2Frame(&$parsedFrame) { // Adjustment $xx (xx ...) $frame_offset = 0; - $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1); + $parsedFrame['adjustmentbits'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8); $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset); diff --git a/src/Module/Tag/Lyrics3.php b/src/Module/Tag/Lyrics3.php index 79fe20e6..7df62196 100644 --- a/src/Module/Tag/Lyrics3.php +++ b/src/Module/Tag/Lyrics3.php @@ -274,7 +274,7 @@ public function getLyrics3Data($endoffset, $version, $length) { */ public function Lyrics3Timestamp2Seconds($rawtimestamp) { if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) { - return (int) (($regs[1] * 60) + $regs[2]); + return (int) (((int) $regs[1] * 60) + (int) $regs[2]); } return false; } diff --git a/src/Utils.php b/src/Utils.php index 8f2dae44..8979bc9d 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -265,7 +265,9 @@ public static function intValueSupported($num) { // check if integers are 64-bit if (static::$hasINT64 === null) { - static::$hasINT64 = is_int(pow(2, 31)); + /** @var int|float|false $bigInt */ + $bigInt = pow(2, 31); + static::$hasINT64 = is_int($bigInt); // 32-bit int are limited to (2^31)-1 } // if integers are 64-bit - no other check required if (static::$hasINT64) { @@ -894,16 +896,36 @@ public static function array_min($arraydata, $returnkey=false) { * @return array|false */ public static function XML2array($XMLstring) { - if (function_exists('simplexml_load_string') && function_exists('libxml_disable_entity_loader')) { - // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html - // https://core.trac.wordpress.org/changeset/29378 - // This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is - // disabled by default, but is still needed when LIBXML_NOENT is used. - $loader = @libxml_disable_entity_loader(true); - $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_COMPACT); - $return = self::SimpleXMLelement2array($XMLobject); - @libxml_disable_entity_loader($loader); - return $return; + if (function_exists('simplexml_load_string')) { + if (PHP_VERSION_ID < 80000) { + if (function_exists('libxml_disable_entity_loader')) { + // http://websec.io/2012/08/27/Preventing-XEE-in-PHP.html + // https://core.trac.wordpress.org/changeset/29378 + // This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is + // disabled by default, but is still needed when LIBXML_NOENT is used. + $loader = @libxml_disable_entity_loader(true); + $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_COMPACT); + $return = self::SimpleXMLelement2array($XMLobject); + @libxml_disable_entity_loader($loader); + return $return; + } + } else { + $allow = false; + if (defined('LIBXML_VERSION') && (LIBXML_VERSION >= 20900)) { + // https://www.php.net/manual/en/function.libxml-disable-entity-loader.php + // "as of libxml 2.9.0 entity substitution is disabled by default, so there is no need to disable the loading + // of external entities, unless there is the need to resolve internal entity references with LIBXML_NOENT." + $allow = true; + } elseif (function_exists('libxml_set_external_entity_loader')) { + libxml_set_external_entity_loader(function () { return null; }); // https://www.zend.com/blog/cve-2023-3823 + $allow = true; + } + if ($allow) { + $XMLobject = simplexml_load_string($XMLstring, 'SimpleXMLElement', LIBXML_NOENT | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_COMPACT); + $return = self::SimpleXMLelement2array($XMLobject); + return $return; + } + } } return false; } @@ -1646,7 +1668,7 @@ public static function RGADamplitude2dB($amplitude) { */ public static function GetDataImageSize($imgData, &$imageinfo=array()) { $GetDataImageSize = @getimagesizefromstring($imgData, $imageinfo); - if ($GetDataImageSize === false || !isset($GetDataImageSize[0], $GetDataImageSize[1])) { + if ($GetDataImageSize === false) { return false; } $GetDataImageSize['height'] = $GetDataImageSize[0]; diff --git a/src/Write/ID3v2.php b/src/Write/ID3v2.php index 7bf46329..0533fc77 100644 --- a/src/Write/ID3v2.php +++ b/src/Write/ID3v2.php @@ -247,7 +247,7 @@ public function RemoveID3v2() { fwrite($fp_temp, $buffer, strlen($buffer)); } fclose($fp_source); - if (Utils::isWritable($this->filename) && ($fp_source = fopen($this->filename, 'wb'))) { + if ($fp_source = fopen($this->filename, 'wb')) { rewind($fp_temp); while ($buffer = fread($fp_temp, $this->fread_buffer_size)) { fwrite($fp_source, $buffer, strlen($buffer));