diff --git a/wp-includes/ID3/getid3.lib.php b/wp-includes/ID3/getid3.lib.php index 5242ce643f..aec550b30d 100644 --- a/wp-includes/ID3/getid3.lib.php +++ b/wp-includes/ID3/getid3.lib.php @@ -121,12 +121,24 @@ class getid3_lib } } // if integers are 64-bit - no other check required - if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { // phpcs:ignore PHPCompatibility.Constants.NewConstants.php_int_minFound + if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { return true; } return false; } + /** + * Perform a division, guarding against division by zero + * + * @param float|int $numerator + * @param float|int $denominator + * @param float|int $fallback + * @return float|int + */ + public static function SafeDiv($numerator, $denominator, $fallback = 0) { + return $denominator ? $numerator / $denominator : $fallback; + } + /** * @param string $fraction * @@ -134,7 +146,7 @@ class getid3_lib */ public static function DecimalizeFraction($fraction) { list($numerator, $denominator) = explode('/', $fraction); - return $numerator / ($denominator ? $denominator : 1); + return (int) $numerator / ($denominator ? $denominator : 1); } /** @@ -871,10 +883,6 @@ class getid3_lib * @return string */ public static function iconv_fallback_iso88591_utf8($string, $bom=false) { - if (function_exists('utf8_encode')) { - return utf8_encode($string); - } - // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) $newcharstring = ''; if ($bom) { $newcharstring .= "\xEF\xBB\xBF"; @@ -943,10 +951,6 @@ class getid3_lib * @return string */ public static function iconv_fallback_utf8_iso88591($string) { - if (function_exists('utf8_decode')) { - return utf8_decode($string); - } - // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) $newcharstring = ''; $offset = 0; $stringlength = strlen($string); diff --git a/wp-includes/ID3/getid3.php b/wp-includes/ID3/getid3.php index 760e76c811..6f428554a6 100644 --- a/wp-includes/ID3/getid3.php +++ b/wp-includes/ID3/getid3.php @@ -387,7 +387,7 @@ class getID3 */ protected $startup_warning = ''; - const VERSION = '1.9.22-202207161647'; + const VERSION = '1.9.23-202310190849'; const FREAD_BUFFER_SIZE = 32768; const ATTACHMENTS_NONE = false; @@ -438,19 +438,19 @@ class getID3 $this->startup_error .= 'WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", getID3 cannot run with this setting (bitmask 2 (string functions) cannot be set). Recommended to disable entirely.'."\n"; } - // check for magic quotes in PHP < 7.4.0 (when these functions became deprecated) - if (version_compare(PHP_VERSION, '7.4.0', '<')) { + // check for magic quotes in PHP < 5.4.0 (when these options were removed and getters always return false) + if (version_compare(PHP_VERSION, '5.4.0', '<')) { // Check for magic_quotes_runtime if (function_exists('get_magic_quotes_runtime')) { // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.get_magic_quotes_runtimeDeprecated - if (get_magic_quotes_runtime()) { + if (get_magic_quotes_runtime()) { // @phpstan-ignore-line $this->startup_error .= 'magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'."\n"; } } // Check for magic_quotes_gpc if (function_exists('get_magic_quotes_gpc')) { // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.get_magic_quotes_gpcDeprecated - if (get_magic_quotes_gpc()) { + if (get_magic_quotes_gpc()) { // @phpstan-ignore-line $this->startup_error .= 'magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'."\n"; } } @@ -1468,6 +1468,16 @@ class getID3 'fail_ape' => 'ERROR', ), + // XZ - data - XZ compressed data + '7zip' => array( + 'pattern' => '^7z\\xBC\\xAF\\x27\\x1C', + 'group' => 'archive', + 'module' => '7zip', + 'mime_type' => 'application/x-7z-compressed', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + // Misc other formats @@ -1982,7 +1992,7 @@ class getID3 } $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; - $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; + $this->info['video']['compression_ratio'] = getid3_lib::SafeDiv($BitrateCompressed, $BitrateUncompressed, 1); return true; } @@ -2188,6 +2198,8 @@ abstract class getid3_handler } /** + * @phpstan-impure + * * @return int|bool */ protected function ftell() { @@ -2200,6 +2212,8 @@ abstract class getid3_handler /** * @param int $bytes * + * @phpstan-impure + * * @return string|false * * @throws getid3_exception @@ -2245,6 +2259,8 @@ abstract class getid3_handler * @param int $bytes * @param int $whence * + * @phpstan-impure + * * @return int * * @throws getid3_exception @@ -2286,6 +2302,8 @@ abstract class getid3_handler } /** + * @phpstan-impure + * * @return string|false * * @throws getid3_exception @@ -2341,6 +2359,8 @@ abstract class getid3_handler } /** + * @phpstan-impure + * * @return bool */ protected function feof() { diff --git a/wp-includes/ID3/license.commercial.txt b/wp-includes/ID3/license.commercial.txt deleted file mode 100644 index 416e5a1469..0000000000 --- a/wp-includes/ID3/license.commercial.txt +++ /dev/null @@ -1,27 +0,0 @@ - getID3() Commercial License - =========================== - -getID3() is licensed under the "GNU Public License" (GPL) and/or the -"getID3() Commercial License" (gCL). This document describes the gCL. - ---------------------------------------------------------------------- - -The license is non-exclusively granted to a single person or company, -per payment of the license fee, for the lifetime of that person or -company. The license is non-transferrable. - -The gCL grants the licensee the right to use getID3() in commercial -closed-source projects. Modifications may be made to getID3() with no -obligation to release the modified source code. getID3() (or pieces -thereof) may be included in any number of projects authored (in whole -or in part) by the licensee. - -The licensee may use any version of getID3(), past, present or future, -as is most convenient. This license does not entitle the licensee to -receive any technical support, updates or bugfixes, except as such are -made publicly available to all getID3() users. - -The licensee may not sub-license getID3() itself, meaning that any -commercially released product containing all or parts of getID3() must -have added functionality beyond what is available in getID3(); -getID3() itself may not be re-licensed by the licensee. diff --git a/wp-includes/ID3/license.txt b/wp-includes/ID3/license.txt index c67873ae69..8978b4a212 100644 --- a/wp-includes/ID3/license.txt +++ b/wp-includes/ID3/license.txt @@ -20,7 +20,8 @@ GNU LGPL: https://gnu.org/licenses/lgpl.html (v3) Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2) -getID3 Commercial License: https://www.getid3.org/#gCL (payment required) +getID3 Commercial License: https://www.getid3.org/#gCL +(no longer available, existing licenses remain valid) ***************************************************************** ***************************************************************** diff --git a/wp-includes/ID3/module.audio-video.asf.php b/wp-includes/ID3/module.audio-video.asf.php index e83de75462..4d3d377ddb 100644 --- a/wp-includes/ID3/module.audio-video.asf.php +++ b/wp-includes/ID3/module.audio-video.asf.php @@ -193,7 +193,7 @@ class getid3_asf extends getid3_handler $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000); //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate']; - $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds']; + $info['bitrate'] = getid3_lib::SafeDiv($thisfile_asf_filepropertiesobject['filesize'] * 8, $info['playtime_seconds']); } break; @@ -1066,7 +1066,7 @@ class getid3_asf extends getid3_handler break; } - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { + 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) { if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate']; @@ -1152,7 +1152,7 @@ class getid3_asf extends getid3_handler $videomediaoffset += 4; $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { + 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) { if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate']; diff --git a/wp-includes/ID3/module.audio-video.matroska.php b/wp-includes/ID3/module.audio-video.matroska.php index 128e614e2c..eb5febf433 100644 --- a/wp-includes/ID3/module.audio-video.matroska.php +++ b/wp-includes/ID3/module.audio-video.matroska.php @@ -292,12 +292,12 @@ class getid3_matroska extends getid3_handler $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']); $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']); - if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } - if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } - if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } - if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } - if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } - if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } + if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } + if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } + if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } + if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } + if (!empty($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } + if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } switch ($trackarray['CodecID']) { case 'V_MS/VFW/FOURCC': diff --git a/wp-includes/ID3/module.audio-video.quicktime.php b/wp-includes/ID3/module.audio-video.quicktime.php index 577d3adabf..d6e0eda7dd 100644 --- a/wp-includes/ID3/module.audio-video.quicktime.php +++ b/wp-includes/ID3/module.audio-video.quicktime.php @@ -152,7 +152,7 @@ class getid3_quicktime extends getid3_handler } 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); } elseif (strlen($lat_deg) == 6) { // [+-]DDMMSS.S - $ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(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) * 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); } if (strlen($lon_deg) == 3) { // [+-]DDD.D @@ -160,7 +160,7 @@ class getid3_quicktime extends getid3_handler } 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); } elseif (strlen($lon_deg) == 7) { // [+-]DDDMMSS.S - $ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(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) * 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); } if (strlen($alt_deg) == 3) { // [+-]DDD.D @@ -168,7 +168,7 @@ class getid3_quicktime extends getid3_handler } 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); } elseif (strlen($alt_deg) == 7) { // [+-]DDDMMSS.S - $ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(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) * 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); } foreach (array('latitude', 'longitude', 'altitude') as $key) { @@ -332,7 +332,7 @@ class getid3_quicktime extends getid3_handler } } elseif (isset($value_array['time_to_sample_table'])) { foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) { - if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) { + if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0) && !empty($info['quicktime']['time_scale'])) { $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3); $framecount = $value_array2['sample_count']; } @@ -776,8 +776,8 @@ class getid3_quicktime extends getid3_handler case 'stsd': // Sample Table Sample Description atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); // see: https://github.com/JamesHeinrich/getID3/issues/111 @@ -805,7 +805,6 @@ class getid3_quicktime extends getid3_handler $stsdEntriesDataOffset += 2; $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); - if (substr($atom_structure['sample_description_table'][$i]['data'], 1, 54) == 'application/octet-stream;type=com.parrot.videometadata') { // special handling for apparently-malformed (TextMetaDataSampleEntry?) data for some version of Parrot drones $atom_structure['sample_description_table'][$i]['parrot_frame_metadata']['mime_type'] = substr($atom_structure['sample_description_table'][$i]['data'], 1, 55); @@ -893,7 +892,8 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in break; case 'mp4a': - default: + $atom_structure['sample_description_table'][$i]['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_structure['sample_description_table'][$i]['data'], 20), $baseoffset + $stsdEntriesDataOffset - 20 - 16, $atomHierarchy, $ParseAllPossibleAtoms); + $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; @@ -919,6 +919,9 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in break; } break; + + default: + break; } break; @@ -1666,7 +1669,7 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in ); $atom_structure['data'] = $atom_data; $atom_structure['image_mime'] = 'image/jpeg'; - $atom_structure['description'] = isset($descriptions[$atomname]) ? $descriptions[$atomname] : 'Nikon preview image'; + $atom_structure['description'] = $descriptions[$atomname]; $info['quicktime']['comments']['picture'][] = array( 'image_mime' => $atom_structure['image_mime'], 'data' => $atom_data, @@ -1683,7 +1686,7 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in case 'NCHD': // Nikon:MakerNoteVersion - https://exiftool.org/TagNames/Nikon.html $makerNoteVersion = ''; for ($i = 0, $iMax = strlen($atom_data); $i < $iMax; ++$i) { - if (ord($atom_data[$i]) >= 0x00 && ord($atom_data[$i]) <= 0x1F) { + if (ord($atom_data[$i]) <= 0x1F) { $makerNoteVersion .= ' '.ord($atom_data[$i]); } else { $makerNoteVersion .= $atom_data[$i]; @@ -2101,6 +2104,97 @@ $this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in break; + case 'esds': // Elementary Stream DeScriptor + // https://github.com/JamesHeinrich/getID3/issues/414 + // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.cc + // https://chromium.googlesource.com/chromium/src/media/+/refs/heads/main/formats/mp4/es_descriptor.h + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); // hardcoded: 0x00 + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x000000 + $esds_offset = 4; + + $atom_structure['ES_DescrTag'] = getid3_lib::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'.getid3_lib::PrintHexBytes($atom_structure['ES_DescrTag']).'), at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_DescrSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_ID'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + $atom_structure['ES_flagsraw'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + $atom_structure['ES_flags']['stream_dependency'] = (bool) ($atom_structure['ES_flagsraw'] & 0x80); + $atom_structure['ES_flags']['url_flag'] = (bool) ($atom_structure['ES_flagsraw'] & 0x40); + $atom_structure['ES_flags']['ocr_stream'] = (bool) ($atom_structure['ES_flagsraw'] & 0x20); + $atom_structure['ES_stream_priority'] = ($atom_structure['ES_flagsraw'] & 0x1F); + if ($atom_structure['ES_flags']['url_flag']) { + $this->warning('Unsupported esds.url_flag enabled at offset '.$atom_structure['offset']); + break; + } + if ($atom_structure['ES_flags']['stream_dependency']) { + $atom_structure['ES_dependsOn_ES_ID'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + } + if ($atom_structure['ES_flags']['ocr_stream']) { + $atom_structure['ES_OCR_ES_Id'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 2)); + $esds_offset += 2; + } + + $atom_structure['ES_DecoderConfigDescrTag'] = getid3_lib::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'.getid3_lib::PrintHexBytes($atom_structure['ES_DecoderConfigDescrTag']).'), at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_DecoderConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_objectTypeIndication'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + // https://stackoverflow.com/questions/3987850 + // 0x40 = "Audio ISO/IEC 14496-3" = MPEG-4 Audio + // 0x67 = "Audio ISO/IEC 13818-7 LowComplexity Profile" = MPEG-2 AAC LC + // 0x69 = "Audio ISO/IEC 13818-3" = MPEG-2 Backward Compatible Audio (MPEG-2 Layers 1, 2, and 3) + // 0x6B = "Audio ISO/IEC 11172-3" = MPEG-1 Audio (MPEG-1 Layers 1, 2, and 3) + + $streamTypePlusFlags = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 1)); + $esds_offset += 1; + $atom_structure['ES_streamType'] = ($streamTypePlusFlags & 0xFC) >> 2; + $atom_structure['ES_upStream'] = (bool) ($streamTypePlusFlags & 0x02) >> 1; + $atom_structure['ES_bufferSizeDB'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 3)); + $esds_offset += 3; + $atom_structure['ES_maxBitrate'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 4)); + $esds_offset += 4; + $atom_structure['ES_avgBitrate'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, 4)); + $esds_offset += 4; + if ($atom_structure['ES_avgBitrate']) { + $info['quicktime']['audio']['bitrate'] = $atom_structure['ES_avgBitrate']; + $info['audio']['bitrate'] = $atom_structure['ES_avgBitrate']; + } + + $atom_structure['ES_DecSpecificInfoTag'] = getid3_lib::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'.getid3_lib::PrintHexBytes($atom_structure['ES_DecSpecificInfoTag']).'), at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_DecSpecificInfoTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_DecSpecificInfo'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_DecSpecificInfoTagSize'])); + $esds_offset += $atom_structure['ES_DecSpecificInfoTagSize']; + + $atom_structure['ES_SLConfigDescrTag'] = getid3_lib::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'.getid3_lib::PrintHexBytes($atom_structure['ES_SLConfigDescrTag']).'), at offset '.$atom_structure['offset']); + break; + } + $atom_structure['ES_SLConfigDescrTagSize'] = $this->quicktime_read_mp4_descr_length($atom_data, $esds_offset); + + $atom_structure['ES_SLConfigDescr'] = getid3_lib::BigEndian2Int(substr($atom_data, $esds_offset, $atom_structure['ES_SLConfigDescrTagSize'])); + $esds_offset += $atom_structure['ES_SLConfigDescrTagSize']; + break; + // AVIF-related - https://docs.rs/avif-parse/0.13.2/src/avif_parse/boxes.rs.html case 'pitm': // Primary ITeM case 'iloc': // Item LOCation @@ -2991,6 +3085,7 @@ $this->error('fragmented mp4 files not currently supported'); return array(); } + /** * @param array $info * diff --git a/wp-includes/ID3/module.audio-video.riff.php b/wp-includes/ID3/module.audio-video.riff.php index e745ec65f4..a94ae24d0c 100644 --- a/wp-includes/ID3/module.audio-video.riff.php +++ b/wp-includes/ID3/module.audio-video.riff.php @@ -214,7 +214,7 @@ class getid3_riff extends getid3_handler $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + $info['playtime_seconds'] = (float)getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $thisfile_audio['bitrate']); } $thisfile_audio['lossless'] = false; @@ -440,11 +440,11 @@ class getid3_riff extends getid3_handler $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); - $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000); + $thisfile_riff_WAVE['iXML'][0]['master_speed'] = (int) $numerator / ($denominator ? $denominator : 1000); } if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); - $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000); + $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = (int) $numerator / ($denominator ? $denominator : 1000); } if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); @@ -521,7 +521,7 @@ class getid3_riff extends getid3_handler if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + $info['playtime_seconds'] = (float)getid3_lib::SafeDiv((($info['avdataend'] - $info['avdataoffset']) * 8), $thisfile_audio['bitrate']); } if (!empty($info['wavpack'])) { @@ -531,7 +531,7 @@ class getid3_riff extends getid3_handler // Reset to the way it was - RIFF parsing will have messed this up $info['avdataend'] = $Original['avdataend']; - $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + $thisfile_audio['bitrate'] = getid3_lib::SafeDiv(($info['avdataend'] - $info['avdataoffset']) * 8, $info['playtime_seconds']); $this->fseek($info['avdataoffset'] - 44); $RIFFdata = $this->fread(44); @@ -632,7 +632,7 @@ class getid3_riff extends getid3_handler } } if ($info['avdataend'] > $info['filesize']) { - switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') { + switch ($thisfile_audio_dataformat) { case 'wavpack': // WavPack case 'lpac': // LPAC case 'ofr': // OptimFROG @@ -672,7 +672,7 @@ class getid3_riff extends getid3_handler $this->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); } } - if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { + if ($thisfile_audio_dataformat == 'ac3') { unset($thisfile_audio['bits_per_sample']); if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; @@ -781,15 +781,15 @@ class getid3_riff extends getid3_handler /** @var array $thisfile_riff_video_current */ $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; - if ($thisfile_riff_raw_avih['dwWidth'] > 0) { + if ($thisfile_riff_raw_avih['dwWidth'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; } - if ($thisfile_riff_raw_avih['dwHeight'] > 0) { + if ($thisfile_riff_raw_avih['dwHeight'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; } - if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { + if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { // @phpstan-ignore-line $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; } @@ -1913,7 +1913,7 @@ class getid3_riff extends getid3_handler if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { unset($RIFFchunk[$chunkname][$thisindex]); } - if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) { + if (count($RIFFchunk[$chunkname]) === 0) { unset($RIFFchunk[$chunkname]); } $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); @@ -2034,7 +2034,7 @@ class getid3_riff extends getid3_handler foreach ($RIFFinfoKeyLookup as $key => $value) { if (isset($RIFFinfoArray[$key])) { foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { - if (trim($commentdata['data']) != '') { + if (!empty($commentdata['data']) && trim($commentdata['data']) != '') { if (isset($CommentsTargetArray[$value])) { $CommentsTargetArray[$value][] = trim($commentdata['data']); } else { diff --git a/wp-includes/ID3/module.audio.mp3.php b/wp-includes/ID3/module.audio.mp3.php index 3d8a9442a9..0d8fee3e5d 100644 --- a/wp-includes/ID3/module.audio.mp3.php +++ b/wp-includes/ID3/module.audio.mp3.php @@ -1380,11 +1380,11 @@ class getid3_mp3 extends getid3_handler $Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] = isset($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]) ? ++$Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])] : 1; $Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] = isset($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]) ? ++$Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]] : 1; if (++$frames_scanned >= $max_frames_scan) { - $pct_data_scanned = ($this->ftell() - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']); + $pct_data_scanned = getid3_lib::SafeDiv($this->ftell() - $info['avdataoffset'], $info['avdataend'] - $info['avdataoffset']); $this->warning('too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'); foreach ($Distribution as $key1 => $value1) { foreach ($value1 as $key2 => $value2) { - $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned); + $Distribution[$key1][$key2] = $pct_data_scanned ? round($value2 / $pct_data_scanned) : 1; } } break; @@ -1475,7 +1475,7 @@ class getid3_mp3 extends getid3_handler $SyncSeekAttemptsMax = 1000; $FirstFrameThisfileInfo = null; while ($SynchSeekOffset < $sync_seek_buffer_size) { - if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { + if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !$this->feof()) { if ($SynchSeekOffset > $sync_seek_buffer_size) { // if a synch's not found within the first 128k bytes, then give up @@ -1490,20 +1490,6 @@ class getid3_mp3 extends getid3_handler unset($info['mpeg']); } return false; - - } elseif (feof($this->getid3->fp)) { - - $this->error('Could not find valid MPEG audio synch before end of file'); - if (isset($info['audio']['bitrate'])) { - unset($info['audio']['bitrate']); - } - if (isset($info['mpeg']['audio'])) { - unset($info['mpeg']['audio']); - } - if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) { - unset($info['mpeg']); - } - return false; } } @@ -1652,7 +1638,7 @@ class getid3_mp3 extends getid3_handler } $frames_scanned++; if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) { - $this_pct_scanned = ($this->ftell() - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']); + $this_pct_scanned = getid3_lib::SafeDiv($this->ftell() - $scan_start_offset[$current_segment], $info['avdataend'] - $info['avdataoffset']); if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) { // file likely contains < $max_frames_scan, just scan as one segment $max_scan_segments = 1; @@ -1743,6 +1729,10 @@ class getid3_mp3 extends getid3_handler } $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + if ($info['audio']['channels'] < 1) { + $this->error('Corrupt MP3 file: no channels'); + return false; + } $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode']; $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; return true; diff --git a/wp-includes/ID3/module.audio.ogg.php b/wp-includes/ID3/module.audio.ogg.php index 0cbea61e2f..ebd2b946c5 100644 --- a/wp-includes/ID3/module.audio.ogg.php +++ b/wp-includes/ID3/module.audio.ogg.php @@ -210,8 +210,8 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 [' $filedataoffset += 20; $info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor']; - $info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']; - $info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']; + $info['ogg']['skeleton']['fishead']['presentationtime'] = getid3_lib::SafeDiv($info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'], $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']); + $info['ogg']['skeleton']['fishead']['basetime'] = getid3_lib::SafeDiv($info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'], $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']); $info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc']; @@ -288,7 +288,7 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 [' $info['audio']['sample_rate'] = $info['flac']['STREAMINFO']['sample_rate']; $info['audio']['channels'] = $info['flac']['STREAMINFO']['channels']; $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample']; - $info['playtime_seconds'] = $info['flac']['STREAMINFO']['samples_stream'] / $info['flac']['STREAMINFO']['sample_rate']; + $info['playtime_seconds'] = getid3_lib::SafeDiv($info['flac']['STREAMINFO']['samples_stream'], $info['flac']['STREAMINFO']['sample_rate']); } } else { @@ -359,7 +359,7 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 [' return false; } if (!empty($info['audio']['sample_rate'])) { - $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']); + $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) * $info['audio']['sample_rate'] / $info['ogg']['samples']; } } @@ -534,12 +534,12 @@ $this->warning('Ogg Theora (v3) not fully supported in this version of getID3 [' $filedata = $this->fread($this->getid3->fread_buffer_size()); $filedataoffset = 0; - while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) { + while (substr($filedata, $filedataoffset++, 4) != 'OggS') { if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) { // should be found before here return false; } - if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) { + if (($filedataoffset + 28) > strlen($filedata)) { if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === '')) { // get some more data, unless eof, in which case fail return false; diff --git a/wp-includes/ID3/module.tag.apetag.php b/wp-includes/ID3/module.tag.apetag.php index c5502133fc..1305cfb509 100644 --- a/wp-includes/ID3/module.tag.apetag.php +++ b/wp-includes/ID3/module.tag.apetag.php @@ -267,7 +267,7 @@ class getid3_apetag extends getid3_handler case 'cover art (publisher logo)': case 'cover art (recording)': case 'cover art (studio)': - // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html + // list of possible cover arts from https://github.com/mono/taglib-sharp/blob/taglib-sharp-2.0.3.2/src/TagLib/Ape/Tag.cs if (is_array($thisfile_ape_items_current['data'])) { $this->warning('APEtag "'.$item_key.'" should be flagged as Binary data, but was incorrectly flagged as UTF-8'); $thisfile_ape_items_current['data'] = implode("\x00", $thisfile_ape_items_current['data']); @@ -332,7 +332,7 @@ class getid3_apetag extends getid3_handler $info['ape']['comments']['picture'][] = $comments_picture_data; unset($comments_picture_data); } - } while (false); + } while (false); // @phpstan-ignore-line break; default: diff --git a/wp-includes/ID3/module.tag.id3v1.php b/wp-includes/ID3/module.tag.id3v1.php index b1de25784b..442aefe35c 100644 --- a/wp-includes/ID3/module.tag.id3v1.php +++ b/wp-includes/ID3/module.tag.id3v1.php @@ -66,7 +66,7 @@ class getid3_id3v1 extends getid3_handler if (!empty($ParsedID3v1['genre'])) { unset($ParsedID3v1['genreid']); } - if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) { + if (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown')) { unset($ParsedID3v1['genre']); } diff --git a/wp-includes/ID3/module.tag.id3v2.php b/wp-includes/ID3/module.tag.id3v2.php index 9e7b4eb1bb..ec448be87b 100644 --- a/wp-includes/ID3/module.tag.id3v2.php +++ b/wp-includes/ID3/module.tag.id3v2.php @@ -1494,7 +1494,7 @@ class getid3_id3v2 extends getid3_handler unset($comments_picture_data); } } - } while (false); + } while (false); // @phpstan-ignore-line } } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object @@ -3753,18 +3753,12 @@ class getid3_id3v2 extends getid3_handler * @return bool */ public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) { - for ($i = 0; $i < strlen($numberstring); $i++) { - if ((chr($numberstring[$i]) < chr('0')) || (chr($numberstring[$i]) > chr('9'))) { - if (($numberstring[$i] == '.') && $allowdecimal) { - // allowed - } elseif (($numberstring[$i] == '-') && $allownegative && ($i == 0)) { - // allowed - } else { - return false; - } - } - } - return true; + $pattern = '#^'; + $pattern .= ($allownegative ? '\\-?' : ''); + $pattern .= '[0-9]+'; + $pattern .= ($allowdecimal ? '(\\.[0-9]+)?' : ''); + $pattern .= '$#'; + return preg_match($pattern, $numberstring); } /** @@ -3773,10 +3767,7 @@ class getid3_id3v2 extends getid3_handler * @return bool */ public static function IsValidDateStampString($datestamp) { - if (strlen($datestamp) != 8) { - return false; - } - if (!self::IsANumber($datestamp, false)) { + if (!preg_match('#^[12][0-9]{3}[01][0-9][0123][0-9]$#', $datestamp)) { return false; } $year = substr($datestamp, 0, 4); diff --git a/wp-includes/ID3/readme.txt b/wp-includes/ID3/readme.txt index 0888bc4de2..c1b3d47bff 100644 --- a/wp-includes/ID3/readme.txt +++ b/wp-includes/ID3/readme.txt @@ -20,7 +20,8 @@ GNU LGPL: https://gnu.org/licenses/lgpl.html (v3) Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2) -getID3 Commercial License: https://www.getid3.org/#gCL (payment required) +getID3 Commercial License: https://www.getid3.org/#gCL +(no longer available, existing licenses remain valid) ***************************************************************** ***************************************************************** diff --git a/wp-includes/version.php b/wp-includes/version.php index e8c551cdaf..ce164d9119 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.5-alpha-56974'; +$wp_version = '6.5-alpha-56975'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.