/** * @return bool */ public function DeleteMetaFLAC() { if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted'; return false; } $oldignoreuserabort = ignore_user_abort(true); if (GetId3Core::environmentIsWindows()) { if (file_exists(GetId3Core::getHelperAppsDir() . 'metaflac.exe')) { // To at least see if there was a problem, compare file modification timestamps before and after writing clearstatcache(); $timestampbeforewriting = filemtime($this->filename); $commandline = GetId3Core::getHelperAppsDir() . 'metaflac.exe --remove-all-tags "' . $this->filename . '" 2>&1'; $metaflacError = `{$commandline}`; if (empty($metaflacError)) { clearstatcache(); if ($timestampbeforewriting == filemtime($this->filename)) { $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted'; } } } else { $metaflacError = 'metaflac.exe not found in ' . GetId3Core::getHelperAppsDir(); } } else { // It's simpler on *nix $commandline = 'metaflac --remove-all-tags "' . $this->filename . '" 2>&1'; $metaflacError = `{$commandline}`; } ignore_user_abort($oldignoreuserabort); if (!empty($metaflacError)) { $this->errors[] = 'System call to metaflac failed with this message returned: ' . "\n\n" . $metaflacError; return false; } return true; }
/** * self::md5_data() - returns md5sum for a file from startuing position to absolute end position * * @staticvar string $tempdir * * @param type $file * @param type $offset * @param type $end * @param type $algorithm * * @return bool * * @throws Exception * * @author Allan Hansen <ahØartemis*dk> */ public static function hash_data($file, $offset, $end, $algorithm) { static $tempdir = ''; if (!self::intValueSupported($end)) { return false; } switch ($algorithm) { case 'md5': $hash_function = 'md5_file'; $unix_call = 'md5sum'; $windows_call = 'md5sum.exe'; $hash_length = 32; break; case 'sha1': $hash_function = 'sha1_file'; $unix_call = 'sha1sum'; $windows_call = 'sha1sum.exe'; $hash_length = 40; break; default: throw new DefaultException('Invalid algorithm (' . $algorithm . ') in self::hash_data()'); break; } $size = $end - $offset; while (true) { if (GetId3Core::environmentIsWindows()) { // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data // Fall back to create-temp-file method: if ($algorithm == 'sha1') { break; } $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call); foreach ($RequiredFiles as $required_file) { if (!is_readable(GetId3Core::getHelperAppsDir() . $required_file)) { // helper apps not available - fall back to old method break 2; } } $commandline = GetId3Core::getHelperAppsDir() . 'head.exe -c ' . $end . ' ' . escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)) . ' | '; $commandline .= GetId3Core::getHelperAppsDir() . 'tail.exe -c ' . $size . ' | '; $commandline .= GetId3Core::getHelperAppsDir() . $windows_call; } else { $commandline = 'head -c' . $end . ' ' . escapeshellarg($file) . ' | '; $commandline .= 'tail -c' . $size . ' | '; $commandline .= $unix_call; } if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { //throw new DefaultException('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm'); break; } return substr(`{$commandline}`, 0, $hash_length); } if (empty($tempdir)) { // yes this is ugly, feel free to suggest a better way $getid3_temp = new GetId3Core(); $tempdir = $getid3_temp->tempdir; unset($getid3_temp); } // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir if (($data_filename = tempnam($tempdir, 'gI3')) === false) { // can't find anywhere to create a temp file, just fail return false; } // Init $result = false; // copy parts of file try { self::CopyFileParts($file, $data_filename, $offset, $end - $offset); $result = $hash_function($data_filename); } catch (DefaultException $e) { throw new DefaultException('self::CopyFileParts() failed in getid_lib::hash_data(): ' . $e->getMessage()); } unlink($data_filename); return $result; }
/** * @return bool */ public function WriteVorbisComment() { if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written'; return false; } // Create file with new comments $tempcommentsfilename = tempnam(GetId3Core::getTempDir(), 'getID3'); if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) { foreach ($this->tag_data as $key => $value) { foreach ($value as $commentdata) { fwrite($fpcomments, $this->CleanVorbisCommentName($key) . '=' . $commentdata . "\n"); } } fclose($fpcomments); } else { $this->errors[] = 'failed to open temporary tags file "' . $tempcommentsfilename . '", tags not written'; return false; } $oldignoreuserabort = ignore_user_abort(true); if (GetId3Core::environmentIsWindows()) { if (file_exists(GetId3Core::getHelperAppsDir() . 'vorbiscomment.exe')) { //$commandline = '"'.GetId3Core::getHelperAppsDir().'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; // vorbiscomment works fine if you copy-paste the above commandline into a command prompt, // but refuses to work with `backtick` if there are "doublequotes" present around BOTH // the metaflac pathname and the target filename. For whatever reason...?? // The solution is simply ensure that the metaflac pathname has no spaces, // and therefore does not need to be quoted // On top of that, if error messages are not always captured properly under Windows // To at least see if there was a problem, compare file modification timestamps before and after writing clearstatcache(); $timestampbeforewriting = filemtime($this->filename); $commandline = GetId3Core::getHelperAppsDir() . 'vorbiscomment.exe -w --raw -c "' . $tempcommentsfilename . '" "' . $this->filename . '" 2>&1'; $VorbiscommentError = `{$commandline}`; if (empty($VorbiscommentError)) { clearstatcache(); if ($timestampbeforewriting == filemtime($this->filename)) { $VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written'; } } } else { $VorbiscommentError = 'vorbiscomment.exe not found in ' . GetId3Core::getHelperAppsDir(); } } else { $commandline = 'vorbiscomment -w --raw -c "' . $tempcommentsfilename . '" "' . $this->filename . '" 2>&1'; $VorbiscommentError = `{$commandline}`; } // Remove temporary comments file unlink($tempcommentsfilename); ignore_user_abort($oldignoreuserabort); if (!empty($VorbiscommentError)) { $this->errors[] = 'system call to vorbiscomment failed with message: ' . "\n\n" . $VorbiscommentError; return false; } return true; }
/** * @staticvar type $shorten_present * * @return bool */ public function analyze() { $info =& $this->getid3->info; fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); $ShortenHeader = fread($this->getid3->fp, 8); $magic = 'ajkg'; if (substr($ShortenHeader, 0, 4) != $magic) { $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['avdataoffset'] . ', found "' . Helper::PrintHexBytes(substr($ShortenHeader, 0, 4)) . '"'; return false; } $info['fileformat'] = 'shn'; $info['audio']['dataformat'] = 'shn'; $info['audio']['lossless'] = true; $info['audio']['bitrate_mode'] = 'vbr'; $info['shn']['version'] = Helper::LittleEndian2Int(substr($ShortenHeader, 4, 1)); fseek($this->getid3->fp, $info['avdataend'] - 12, SEEK_SET); $SeekTableSignatureTest = fread($this->getid3->fp, 12); $info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK'); if ($info['shn']['seektable']['present']) { $info['shn']['seektable']['length'] = Helper::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4)); $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length']; fseek($this->getid3->fp, $info['shn']['seektable']['offset'], SEEK_SET); $SeekTableMagic = fread($this->getid3->fp, 4); $magic = 'SEEK'; if ($SeekTableMagic != $magic) { $info['error'][] = 'Expecting "' . Helper::PrintHexBytes($magic) . '" at offset ' . $info['shn']['seektable']['offset'] . ', found "' . Helper::PrintHexBytes($SeekTableMagic) . '"'; return false; } else { // typedef struct tag_TSeekEntry // { // unsigned long SampleNumber; // unsigned long SHNFileByteOffset; // unsigned long SHNLastBufferReadPosition; // unsigned short SHNByteGet; // unsigned short SHNBufferOffset; // unsigned short SHNFileBitOffset; // unsigned long SHNGBuffer; // unsigned short SHNBitShift; // long CBuf0[3]; // long CBuf1[3]; // long Offset0[4]; // long Offset1[4]; // }TSeekEntry; $SeekTableData = fread($this->getid3->fp, $info['shn']['seektable']['length'] - 16); $info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80); //$info['shn']['seektable']['entries'] = array(); //$SeekTableOffset = 0; //for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) { // $SeekTableEntry['sample_number'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_file_byte_offset'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_last_buffer_read_position'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_byte_get'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // $SeekTableEntry['shn_buffer_offset'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // $SeekTableEntry['shn_file_bit_offset'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // $SeekTableEntry['shn_gbuffer'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // $SeekTableEntry['shn_bit_shift'] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); // $SeekTableOffset += 2; // for ($j = 0; $j < 3; $j++) { // $SeekTableEntry['cbuf0'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // for ($j = 0; $j < 3; $j++) { // $SeekTableEntry['cbuf1'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // for ($j = 0; $j < 4; $j++) { // $SeekTableEntry['offset0'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // for ($j = 0; $j < 4; $j++) { // $SeekTableEntry['offset1'][$j] = GetId3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); // $SeekTableOffset += 4; // } // // $info['shn']['seektable']['entries'][] = $SeekTableEntry; //} } } if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { $info['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files'; return false; } if (GetId3Core::environmentIsWindows()) { $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe'); foreach ($RequiredFiles as $required_file) { if (!is_readable(GetId3Core::getHelperAppsDir() . $required_file)) { $info['error'][] = GetId3Core::getHelperAppsDir() . $required_file . ' does not exist'; return false; } } $commandline = GetId3Core::getHelperAppsDir() . 'shorten.exe -x "' . $info['filenamepath'] . '" - | ' . GetId3Core::getHelperAppsDir() . 'head.exe -c 64'; $commandline = str_replace('/', '\\', $commandline); } else { static $shorten_present; if (!isset($shorten_present)) { $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`; } if (!$shorten_present) { $info['error'][] = 'shorten binary was not found in path or /usr/local/bin'; return false; } $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '') . 'shorten -x ' . escapeshellarg($info['filenamepath']) . ' - | head -c 64'; } $output = `{$commandline}`; if (!empty($output) && substr($output, 12, 4) == 'fmt ') { $fmt_size = Helper::LittleEndian2Int(substr($output, 16, 4)); $DecodedWAVFORMATEX = Riff::RIFFparseWAVEFORMATex(substr($output, 20, $fmt_size)); $info['audio']['channels'] = $DecodedWAVFORMATEX['channels']; $info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample']; $info['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate']; if (substr($output, 20 + $fmt_size, 4) == 'data') { $info['playtime_seconds'] = Helper::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']; } else { $info['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime'; return false; } $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds'] * 8; } else { $info['error'][] = 'shorten failed to decode file to WAV for parsing'; return false; } return true; }