aramds / php-reader

code.google.com/p/php-reader
0 stars 0 forks source link

Zend_Media_Id3v2 Crashes when certain metadata fields are present #39

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
When trying to open certain files I get the following message: 

Fatal error: Uncaught exception 'Zend_Media_Id3_Exception' with message 
'Unable to open file for reading: E:\Users\Matt\Music\The Desperation 
Band\Everyone Overcome\Light of Salvation.mp3' in 
C:\wamp\www\ZendFramework-1.10.2\library\Zend\Media\Id3v2.php:119 Stack 
trace: #0 
C:\wamp\www\ratio_blog\local\CodeRepository\Zend_Media\getMp3data.php(24): 
Zend_Media_Id3v2->__construct('E:\Users\Matt\M...') #1 {main} thrown in 
C:\wamp\www\ZendFramework-1.10.2\library\Zend\Media\Id3v2.php on line 119

The file is definitely readable - I'm able to extract data from the same 
file with getId3 (http://getid3.sourceforge.net/).

I also encountered errors where it wouldn't recognize "_data" field which 
would cause it to crash.

I hope that these bugs are able to be worked out as this project is 
obviously much better maintained that getid3 which contains a bunch of 
deprecated ereg functions and hasn't been updated for the past year.  

Original issue reported on code.google.com by mattcdav...@gmail.com on 7 Apr 2010 at 5:52

GoogleCodeExporter commented 9 years ago
The error message you received comes from this block of code:

{{{
if (!file_exists($filename) || !is_readable($filename) ||
    ($fd = fopen($filename, $mode)) === false) {
    require_once('Zend/Io/Exception.php');
    throw new Zend_Io_Exception
        ('Unable to open file for reading: ' . $filename);
}
}}}

Which means that a) file_exists returns false, or b) is_readable returns false, 
or c)
fopen with $mode (which by default is 'rb') returns false. Could you make a 
sample
script that executes each one of those functions for your file that throws the
exception with Id3v2 class and let me know what they return for you.

Can you reproduce the error and is it always the same file that is causing you 
the
trouble?

Can you also elaborate the second problem about the class not recognizing 
'_data'
field. What field? Which class? How does the class crash? Can you post an 
extract of
the trace.

Original comment by svollbehr on 7 Apr 2010 at 8:16

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
The script is attached.  Ideally I want to loop through entire directories 
(which is 
how my script is currently setup with the getId3 class), but I've just uploaded 
the 
bare-minimum to reproduce the issues mentioned above.  The error is in the 
constructor anyway, so anything after that doesn't really make any difference.

The files referred to in the script are available for download on my site at:
http://datacodesolutions.com/download.php

At one point, in trying to troubleshoot the "unknown _data" error, I actually 
opened 
up the .mp3 file in notepad++ and deleted one of the fields(I think it was UFID 
- 
can't remember for sure though) and got it to work.  Obviously though, any 
script 
like this needs to be able to handle any type of error without fatally 
crashing. 

I also downloaded a utility (Mp3tag v2.46a) which allows users to update 
metadata and 
shows when the tags are bad.  It shows all the of the files referred to in the 
script 
as being legitimate ID3v2.3 metadata tags

Original comment by mattcdav...@gmail.com on 8 Apr 2010 at 1:07

Attachments:

GoogleCodeExporter commented 9 years ago
I have debugged your files a bit. Couple of things noted:

  //$filename =
('C:\wamp\www\ratio_blog\local\CodeRepository\debug\Light_of_Salvation.mp3'); 
//Fails with 'Unable to open file for reading'

This is probably due to the fact the file is called 02_Light_of_Salvation.mp3, 
works
when the filename is fixed.

I couldn't reproduce any of the other errors with any of the files. I executed 
your
PHP script and it returned with the following error message for all files:

  Fatal error: Uncaught exception 'Zend_Media_Id3_Exception' with message 'File does
not contain ID3v2 tag'

Which seems quite appropriate after taking a quick look at the files with Hex 
editor.
The files seem to have some garbage before the ID3 header:

  downloads/01_Work.mp3ID3....
  downloads/02_Light_Of_Salvation.mp3ID3...

According to the ID3 specification the 'ID3' (the start of the header) should be
located at the very beginning of the file. How can one otherwise determine 
where to
beging to look for it and for how deep into the file to look. Here's a snippet 
from
the standard.

 The ID3v2 tag header, which should be the first information in the
   file, is 10 bytes as follows:

     ID3v2/file identifier      "ID3"
     ID3v2 version              $03 00
     ID3v2 flags                %abc00000
     ID3v2 size             4 * %0xxxxxxx

  etc..

However, it's quite funny that Windows does actually recognize the ID3 tag 
regardless.

Anyways, I fixed the files by removing that extra garbage from the beginning of 
the
file and I was able to read all the files. I was also able to reproduce the 
Unknown
field: _data exception you got. Here are the results.

  01_Work.mp3 Works ok and contains the following frames: TENC, PRIV, PRIV, PRIV,
PRIV, PRIV, PRIV, PRIV, TPUB, COMM, COMM, TIT2, TPE1, TPE2, TCOM, TALB, TRCK, 
TPOS,
TYER, TCON

  01_Prologue.mp3 Produced Unknown field: _data due to a bug in the UFID class. After
a quick fix it works. File contains the following frames: TALB, TPE1, TPE2, 
COMM,
TPOS, TENC, TCON, POPM, TIT2, TRCK, UFID, TYER.

  02_Light_of_Salvation.mp3 Works okay, after changing the file name. File contains
the following frames: TALB, TPE1, TPE2, COMM, TPOS, TCON, TIT2, TRCK, TYER.

I have committed the fix for UFID into subversion and will also further think 
about
what to do with the file name before the ID3 tag. Thanks for reporting! Try the 
new
code from subversion!

Original comment by svollbehr on 8 Apr 2010 at 2:45

GoogleCodeExporter commented 9 years ago
Tried the updated code with the file that was producing "Unknown Data" issue 
and it 
works great - Thanks!.  

I do have a couple questions:

1.  Is there some way to check that the the files' metadata is not corrupted 
(and 
perhaps fix on the fly) before instantiating the object.  Perhaps some regular 
expression that checks whether "ID3" are the first the characters and, if not, 
extracts all characters up to the pattern "ID3"?  This way my entire script 
won't 
crash if I encounter a bad file.

2.  This is probably more along the lines of a feature request, but the current 
program I'm using ( getId3 from http://getid3.sourceforge.net/ ) outputs the 
following fields for each file:

$ThisFileInfo['avdataoffset']
$ThisFileInfo['avdataend']

Using this information I'm able to determine the length (in seconds) of the 
file with 
a simple formula.  This is critical for me because I'm using the script to 
create a 
feed for itunesU and the length of the file is one of the fields that I need to 
fill 
out.  

Thanks again for the fix!  

Original comment by mattcdav...@gmail.com on 8 Apr 2010 at 4:26

GoogleCodeExporter commented 9 years ago
Yes, for the first question you can just instantiate Zend_Io_FileReader and 
check if
read(3) == 'ID3' (if yes, it contains an Id3v2 tag). If it is successfull you 
can
just set the reader offset back to 0 and use that instance to initialize the 
Id3v2 class.

$reader = new Zend_Io_FileReader('filename');
if ($reader->read(3) == 'ID3) {
  // contains ID3v2
  $reader->offset = 0;
  $id3 = new Zend_Media_Id3v2($reader);
  // ...
}

You could also try to instantiate the class within a try-catch block:

try {
  $id3 = new Zend_Media_Id3v2('filename');
  // ...
} catch (Zend_Media_Exception $e) {
  // skip file, there is no tag
}

Unfortunately the format of the ID3 tag cannot be verified. All unknown frames 
will
be parsed properly though (unless there's a bug somewhere).

As for the second question you cannot just determine the play length based on 
the
number of audio bytes a file contains. The bitrate varies, frame size varies, 
file
could be CBR/VBR. So I don't think any simple formula would do it. However, I 
think
the feature you are longing is already implemented in Zend_Media_Mpeg_Abs (ABS 
as in
Audio Bit Stream). That is a class that actually parses the MPEG audio 
information
and reads the MPEG frame information. You can use that info for example to 
calculate
the exact (or estimated) length of the file. Instantiate that class using the 
file
name (or the reader object) as the parameter and then call the
getFormattedLengthEstimate method to get the file length estimate (quicker than
reading the exact length). If you need the exact length you can go through the 
whole
file by calling getFormattedLength method.

Original comment by svollbehr on 8 Apr 2010 at 9:21

GoogleCodeExporter commented 9 years ago
Thanks dude - you rock!  Everything's running great - including the method you 
suggested for getting the file length.  I'm going to switch to your library for 
all my 
scripts that utilize mp3 metadata.

-matt

Original comment by mattcdav...@gmail.com on 9 Apr 2010 at 3:56

GoogleCodeExporter commented 9 years ago
Anytime..

Original comment by svollbehr on 9 Apr 2010 at 7:32

GoogleCodeExporter commented 9 years ago

Original comment by svollbehr on 6 Jun 2010 at 4:30