Question

When I upload a well-formed MP3 file, Laravel 4 tells me it's not audio/mp3 but application/octet-stream, which makes this validation fails:

$validator = Validator::make(
    array('trackfile' => Input::file('trackfile')), 
    array('trackfile' => 'required|mimes:mp3')
);

if($validator->fails())
    return 'doesn\'t works because mime type is '.Input::file('trackfile')->getMimeType();
else
    return 'it works!';

Why doesn't it upload the file as an audio/mp3 file ?

(I already added 'files' => true to the form declaration)

Était-ce utile?

La solution

Edit

Built-in validator was still considering some mp3's as application/octet-stream, wether you converted the original file with this or that software.

I finally used the MimeReader class by user Shane, which totally works. I'm still wondering why is it so hard to detect a right mime type though.

I implemented it as a validator in Laravel:

  • Move MimeReader.phps in app/libraries/MimeReader.php (watch the extension)
  • Extend the Laravel Validator (I put it in my BaseController constructor)

    Validator::extend('audio', function($attribute, $value, $parameters)
    {
        $allowed = array('audio/mpeg', 'application/ogg', 'audio/wave', 'audio/aiff');
        $mime = new MimeReader($value->getRealPath());
        return in_array($mime->get_type(), $allowed);
    });
    
  • Add your error message in app/lang/[whatever]/validation.php (in my case, the key is audio)
  • I can now use audio as a rule ! Example: 'file' => 'required|audio', where file refers to Input::file('file')

Laravel was considering audio/mpeg files to be .mpga and not .mp3. I corrected it in MimeTypeExtensionGuesser.php (in the Symfony library), along with audio/ogg that were considered as .oga. Maybe the audio mime-type depends on what software encoder was used.

Other method is to bypass the validator and check the mime-type directly into the controller using Input::file('upload')->getMimeType() like Sheikh Heera said.

Autres conseils

It's probably because of mp3 file's mime type is audio/mpeg or could be that, it fails to recognize the mime_content_type and tells application/octet-stream as a generic/fallback type. You may try this rule (example given below) instead (not tested/sure), because audio/mpeg is the correct mime type for mp3 according to rfc3003:

array('trackfile' => 'required|mimes:audio/mpeg,mp3')

Also, you may manually check the mime type using something like this:

$file = Input::file('upload');
if($file->getMimeType() == 'audio/mpeg') {
    // valid
}
else {
    // invalid
}

Update:

Specially, for mp3 files, you may also use a library getID3 which is similar to Php PECL extension id3, if you use it, you will be also able to use ID3 tag of the file and can get information such as title, artist, album, year, genre etc.

If you use it, you have to download it manually from the given link (getid3) and put it in a folder inside app, maybe app/libs/ and just put the getid3 folder from the extracted source into the libs folder then in your composer.json file add an entry inside classmap of autoload section like:

// ...
"app/tests/TestCase.php",
"app/libs/getid3"

Then run composer dump-autoload from terminal/command prompt and you are ready to use it. To use it symply try this:

$file = Input::file('upload'); // assumed name of the file input is upload
$path = $path = $file->getRealPath();
$id3 = new getID3();
$tags = $id3->analyze($path);
if(is_array($tags) && array_key_exists('audio', $tags)) {
    // valid
    dd($tag['tags']);
}

For a valid mp3 file You'll get an array like this:

array (size=2)   'id3v1' => 
    array (size=6)
      'title' => 
        array (size=1)
          0 => string '46. Piya Basanti' (length=16)
      'artist' => 
        array (size=1)
          0 => string '(Freshmaza.com)' (length=15)
      'album' =>
      ...

If you have already installed or can install the PECL extension using (from terminal) following command:

pear install pecl/id3

Then you may normally use

$tags = id3_get_tag( "path/to/example.mp3" );
print_r($tag);

The above example will output something similar to:

Array
(
    [title] => DN-38416
    [artist] => Re:\Legion
    [album] => Reflections
    [year] => 2004
    [genre] => 19
)

Check Php manual.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top