[SPIP] ~maj v3.2.9-->v3.2.11
[lhc/web/www.git] / www / plugins-dist / medias / lib / getid3 / getid3.php
index 90d7c9c..bce97fb 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 /////////////////////////////////////////////////////////////////
 /// getID3() by James Heinrich <info@getid3.org>               //
 //  available at https://github.com/JamesHeinrich/getID3       //
@@ -100,6 +99,13 @@ class getID3
         */
        public $encoding_id3v1  = 'ISO-8859-1';
 
+       /**
+        * ID3v1 should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'Windows-1251' or 'KOI8-R'. If true attempt to detect these encodings, but may return incorrect values for some tags actually in ISO-8859-1 encoding
+        *
+        * @var bool
+        */
+       public $encoding_id3v1_autodetect  = false;
+
        /*
         * Optional tag checks - disable for speed.
         */
@@ -251,7 +257,7 @@ class getID3
         */
        protected $startup_warning = '';
 
-       const VERSION           = '1.9.16-201810171314';
+       const VERSION           = '1.9.20-202006061653';
        const FREAD_BUFFER_SIZE = 32768;
 
        const ATTACHMENTS_NONE   = false;
@@ -267,14 +273,16 @@ class getID3
                }
 
                // Check memory
-               $this->memory_limit = ini_get('memory_limit');
-               if (preg_match('#([0-9]+) ?M#i', $this->memory_limit, $matches)) {
+               $memoryLimit = ini_get('memory_limit');
+               if (preg_match('#([0-9]+) ?M#i', $memoryLimit, $matches)) {
                        // could be stored as "16M" rather than 16777216 for example
-                       $this->memory_limit = $matches[1] * 1048576;
-               } elseif (preg_match('#([0-9]+) ?G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
+                       $memoryLimit = $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
-                       $this->memory_limit = $matches[1] * 1073741824;
+                       $memoryLimit = $matches[1] * 1073741824;
                }
+               $this->memory_limit = $memoryLimit;
+
                if ($this->memory_limit <= 0) {
                        // memory limits probably disabled
                } elseif ($this->memory_limit <= 4194304) {
@@ -288,24 +296,26 @@ class getID3
                        $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
                }
 
-               if (($mbstring_func_overload = ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
+               if (($mbstring_func_overload = (int) ini_get('mbstring.func_overload')) && ($mbstring_func_overload & 0x02)) {
                        // http://php.net/manual/en/mbstring.overload.php
                        // "mbstring.func_overload in php.ini is a positive value that represents a combination of bitmasks specifying the categories of functions to be overloaded. It should be set to 1 to overload the mail() function. 2 for string functions, 4 for regular expression functions"
                        // getID3 cannot run when string functions are overloaded. It doesn't matter if mail() or ereg* functions are overloaded since getID3 does not use those.
                        $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_runtime
-               if (function_exists('get_magic_quotes_runtime')) {
-                       if (get_magic_quotes_runtime()) {
-                               $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 in PHP < 7.4.0 (when these functions became deprecated)
+               if (version_compare(PHP_VERSION, '7.4.0', '<')) {
+                       // Check for magic_quotes_runtime
+                       if (function_exists('get_magic_quotes_runtime')) {
+                               if (get_magic_quotes_runtime()) {
+                                       $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('magic_quotes_gpc')) {
-                       if (get_magic_quotes_gpc()) {
-                               $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";
+                       // Check for magic_quotes_gpc
+                       if (function_exists('get_magic_quotes_gpc')) {
+                               if (get_magic_quotes_gpc()) {
+                                       $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";
+                               }
                        }
                }
 
@@ -321,7 +331,7 @@ class getID3
 
                // Needed for Windows only:
                // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
-               //   as well as other helper functions such as head, tail, md5sum, etc
+               //   as well as other helper functions such as head, etc
                // This path cannot contain spaces, but the below code will attempt to get the
                //   8.3-equivalent path automatically
                // IMPORTANT: This path must include the trailing slash
@@ -399,14 +409,15 @@ class getID3
        }
 
        /**
-        * @param string $filename
-        * @param int    $filesize
+        * @param string   $filename
+        * @param int      $filesize
+        * @param resource $fp
         *
         * @return bool
         *
         * @throws getid3_exception
         */
-       public function openfile($filename, $filesize=null) {
+       public function openfile($filename, $filesize=null, $fp=null) {
                try {
                        if (!empty($this->startup_error)) {
                                throw new getid3_exception($this->startup_error);
@@ -433,7 +444,9 @@ class getID3
 
                        // open local file
                        //if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { // see https://www.getid3.org/phpBB3/viewtopic.php?t=1720
-                       if ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
+                       if (($fp != null) && ((get_resource_type($fp) == 'file') || (get_resource_type($fp) == 'stream'))) {
+                               $this->fp = $fp;
+                       } elseif ((is_readable($filename) || file_exists($filename)) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
                                // great
                        } else {
                                $errormessagelist = array();
@@ -508,15 +521,16 @@ class getID3
        /**
         * analyze file
         *
-        * @param string $filename
-        * @param int    $filesize
-        * @param string $original_filename
+        * @param string   $filename
+        * @param int      $filesize
+        * @param string   $original_filename
+        * @param resource $fp
         *
         * @return array
         */
-       public function analyze($filename, $filesize=null, $original_filename='') {
+       public function analyze($filename, $filesize=null, $original_filename='', $fp=null) {
                try {
-                       if (!$this->openfile($filename, $filesize)) {
+                       if (!$this->openfile($filename, $filesize, $fp)) {
                                return $this->info;
                        }
 
@@ -550,8 +564,8 @@ class getID3
                                $header = fread($this->fp, 10);
                                if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
                                        $this->info['id3v2']['header']        = true;
-                                       $this->info['id3v2']['majorversion']  = ord($header{3});
-                                       $this->info['id3v2']['minorversion']  = ord($header{4});
+                                       $this->info['id3v2']['majorversion']  = ord($header[3]);
+                                       $this->info['id3v2']['minorversion']  = ord($header[4]);
                                        $this->info['avdataoffset']          += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
                                }
                        }
@@ -833,12 +847,20 @@ class getID3
 
                                // DSS  - audio       - Digital Speech Standard
                                'dss'  => array(
-                                                       'pattern'   => '^[\\x02-\\x06]ds[s2]',
+                                                       'pattern'   => '^[\\x02-\\x08]ds[s2]',
                                                        'group'     => 'audio',
                                                        'module'    => 'dss',
                                                        'mime_type' => 'application/octet-stream',
                                                ),
 
+                               // DSDIFF - audio     - Direct Stream Digital Interchange File Format
+                               'dsdiff' => array(
+                                                       'pattern'   => '^FRM8',
+                                                       'group'     => 'audio',
+                                                       'module'    => 'dsdiff',
+                                                       'mime_type' => 'audio/dsd',
+                                               ),
+
                                // DTS  - audio       - Dolby Theatre System
                                'dts'  => array(
                                                        'pattern'   => '^\\x7F\\xFE\\x80\\x01',
@@ -966,6 +988,14 @@ class getID3
                                                        'fail_ape'  => 'ERROR',
                                                ),
 
+                               // TAK  - audio       - Tom's lossless Audio Kompressor
+                               'tak'  => array(
+                                                       'pattern'   => '^tBaK',
+                                                       'group'     => 'audio',
+                                                       'module'    => 'tak',
+                                                       'mime_type' => 'application/octet-stream',
+                                               ),
+
                                // TTA  - audio       - TTA Lossless Audio Compressor (http://tta.corecodec.org)
                                'tta'  => array(
                                                        'pattern'   => '^TTA',  // could also be '^TTA(\\x01|\\x02|\\x03|2|1)'
@@ -1026,6 +1056,14 @@ class getID3
                                                        'mime_type' => 'video/x-flv',
                                                ),
 
+                               // IVF - audio/video - IVF
+                               'ivf' => array(
+                                                       'pattern'   => '^DKIF',
+                                                       'group'     => 'audio-video',
+                                                       'module'    => 'ivf',
+                                                       'mime_type' => 'video/x-ivf',
+                                               ),
+
                                // MKAV - audio/video - Mastroka
                                'matroska' => array(
                                                        'pattern'   => '^\\x1A\\x45\\xDF\\xA3',
@@ -1101,6 +1139,14 @@ class getID3
                                                        'mime_type' => 'video/MP2T',
                                                ),
 
+                               // WTV - audio/video - Windows Recorded TV Show
+                               'wtv' => array(
+                                                       'pattern'   => '^\\xB7\\xD8\\x00\\x20\\x37\\x49\\xDA\\x11\\xA6\\x4E\\x00\\x07\\xE9\\x5E\\xAD\\x8D',
+                                                       'group'     => 'audio-video',
+                                                       'module'    => 'wtv',
+                                                       'mime_type' => 'video/x-ms-wtv',
+                                               ),
+
 
                                // Still-Image formats
 
@@ -1202,12 +1248,22 @@ class getID3
                                                        'iconv_req' => false,
                                                ),
 
+                               // HPK  - data        - HPK compressed data
+                               'hpk'  => array(
+                                                       'pattern'   => '^BPUL',
+                                                       'group'     => 'archive',
+                                                       'module'    => 'hpk',
+                                                       'mime_type' => 'application/octet-stream',
+                                                       'fail_id3'  => 'ERROR',
+                                                       'fail_ape'  => 'ERROR',
+                                               ),
+
                                // RAR  - data        - RAR compressed data
                                'rar'  => array(
                                                        'pattern'   => '^Rar\\!',
                                                        'group'     => 'archive',
                                                        'module'    => 'rar',
-                                                       'mime_type' => 'application/octet-stream',
+                                                       'mime_type' => 'application/vnd.rar',
                                                        'fail_id3'  => 'ERROR',
                                                        'fail_ape'  => 'ERROR',
                                                ),
@@ -1252,6 +1308,16 @@ class getID3
                                                        'fail_ape'  => 'ERROR',
                                                ),
 
+                               // XZ   - data         - XZ compressed data
+                               'xz'  => array(
+                                                       'pattern'   => '^\\xFD7zXZ\\x00',
+                                                       'group'     => 'archive',
+                                                       'module'    => 'xz',
+                                                       'mime_type' => 'application/x-xz',
+                                                       'fail_id3'  => 'ERROR',
+                                                       'fail_ape'  => 'ERROR',
+                                               ),
+
 
                                // Misc other formats
 
@@ -1323,7 +1389,7 @@ class getID3
 
 
                if (preg_match('#\\.mp[123a]$#i', $filename)) {
-                       // Too many mp3 encoders on the market put gabage in front of mpeg files
+                       // Too many mp3 encoders on the market put garbage in front of mpeg files
                        // use assume format on these if format detection failed
                        $GetFileFormatArray = $this->GetFileFormatArray();
                        $info = $GetFileFormatArray['mp3'];
@@ -1399,6 +1465,7 @@ class getID3
                                'flac'      => array('vorbiscomment' , 'UTF-8'),
                                'divxtag'   => array('divx'          , 'ISO-8859-1'),
                                'iptc'      => array('iptc'          , 'ISO-8859-1'),
+                               'dsdiff'    => array('dsdiff'        , 'ISO-8859-1'),
                        );
                }
 
@@ -1427,6 +1494,7 @@ class getID3
                                                }
                                        }
                                        if ($tag_key == 'picture') {
+                                               // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
                                                unset($this->info[$comment_name]['comments'][$tag_key]);
                                        }
                                }
@@ -1440,6 +1508,11 @@ class getID3
 
                                if ($this->option_tags_html) {
                                        foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
+                                               if ($tag_key == 'picture') {
+                                                       // Do not to try to convert binary picture data to HTML
+                                                       // https://github.com/JamesHeinrich/getID3/issues/178
+                                                       continue;
+                                               }
                                                $this->info['tags_html'][$tag_name][$tag_key] = getid3_lib::recursiveMultiByteCharString2HTML($valuearray, $this->info[$comment_name]['encoding']);
                                        }
                                }
@@ -1448,8 +1521,7 @@ class getID3
 
                }
 
-               // pictures can take up a lot of space, and we don't need multiple copies of them
-               // let there be a single copy in [comments][picture], and not elsewhere
+               // pictures can take up a lot of space, and we don't need multiple copies of them; let there be a single copy in [comments][picture], and not elsewhere
                if (!empty($this->info['tags'])) {
                        $unset_keys = array('tags', 'tags_html');
                        foreach ($this->info['tags'] as $tagtype => $tagarray) {
@@ -1495,6 +1567,17 @@ class getID3
                return true;
        }
 
+       /**
+        * Calls getid3_lib::CopyTagsToComments() but passes in the option_tags_html setting from this instance of getID3
+        *
+        * @param array $ThisFileInfo
+        *
+        * @return bool
+        */
+       public function CopyTagsToComments(&$ThisFileInfo) {
+           return getid3_lib::CopyTagsToComments($ThisFileInfo, $this->option_tags_html);
+       }
+
        /**
         * @param string $algorithm
         *
@@ -1508,7 +1591,6 @@ class getID3
 
                        default:
                                return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
-                               break;
                }
 
                if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
@@ -1824,16 +1906,14 @@ class getID3
         *
         * @return bool
         */
-    public static function is_writable ($filename) {
-        $ret = is_writable($filename);
-
-        if (!$ret) {
-            $perms = fileperms($filename);
-            $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
-        }
-
-        return $ret;
-    }
+       public static function is_writable ($filename) {
+               $ret = is_writable($filename);
+               if (!$ret) {
+                       $perms = fileperms($filename);
+                       $ret = ($perms & 0x0080) || ($perms & 0x0010) || ($perms & 0x0002);
+               }
+               return $ret;
+       }
 
 }
 
@@ -1976,7 +2056,8 @@ abstract class getid3_handler
                */
                $contents = '';
                do {
-                       if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
+                       //if (($this->getid3->memory_limit > 0) && ($bytes > $this->getid3->memory_limit)) {
+                       if (($this->getid3->memory_limit > 0) && (($bytes / $this->getid3->memory_limit) > 0.99)) { // enable a more-fuzzy match to prevent close misses generating errors like "PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 33554464 bytes)"
                                throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') that is more than available PHP memory ('.$this->getid3->memory_limit.')', 10);
                        }
                        $part = fread($this->getid3->fp, $bytes);
@@ -2025,6 +2106,61 @@ abstract class getid3_handler
                return fseek($this->getid3->fp, $bytes, $whence);
        }
 
+       /**
+        * @return string|false
+        *
+        * @throws getid3_exception
+        */
+       protected function fgets() {
+               // must be able to handle CR/LF/CRLF but not read more than one lineend
+               $buffer   = ''; // final string we will return
+               $prevchar = ''; // save previously-read character for end-of-line checking
+               if ($this->data_string_flag) {
+                       while (true) {
+                               $thischar = substr($this->data_string, $this->data_string_position++, 1);
+                               if (($prevchar == "\r") && ($thischar != "\n")) {
+                                       // read one byte too many, back up
+                                       $this->data_string_position--;
+                                       break;
+                               }
+                               $buffer .= $thischar;
+                               if ($thischar == "\n") {
+                                       break;
+                               }
+                               if ($this->data_string_position >= $this->data_string_length) {
+                                       // EOF
+                                       break;
+                               }
+                               $prevchar = $thischar;
+                       }
+
+               } else {
+
+                       // Ideally we would just use PHP's fgets() function, however...
+                       // it does not behave consistently with regards to mixed line endings, may be system-dependent
+                       // and breaks entirely when given a file with mixed \r vs \n vs \r\n line endings (e.g. some PDFs)
+                       //return fgets($this->getid3->fp);
+                       while (true) {
+                               $thischar = fgetc($this->getid3->fp);
+                               if (($prevchar == "\r") && ($thischar != "\n")) {
+                                       // read one byte too many, back up
+                                       fseek($this->getid3->fp, -1, SEEK_CUR);
+                                       break;
+                               }
+                               $buffer .= $thischar;
+                               if ($thischar == "\n") {
+                                       break;
+                               }
+                               if (feof($this->getid3->fp)) {
+                                       break;
+                               }
+                               $prevchar = $thischar;
+                       }
+
+               }
+               return $buffer;
+       }
+
        /**
         * @return bool
         */