Pour les besoins du site sur lequel je travaille, j'ai fait cette petite classe, qui permet de "gérer" les tags id3v1, id3v2 (ce dernier étant prioritaire) et vorbis des fichiers mp3 et ogg.
Mais en fait, je m'inquiétais surtout pour sa sécurité, surtout au niveau de la méthode tag(), et je n'ai inclus aucun système d'anti-dépassement (éventuel) de buffer, vu que je ne m'y connais pas du tout.
Si un (ou deux) de vos yeux avisés remarquait un trou à ce niveau, ailleurs, ou quelquechose de codé par les pieds, je serais (très) heureux d'en être averti, afin de pouvoir le recharcuter comme il faut.
<?php
/*
** only support mp3 and ogg tags
** software needed in $PATH : tagtool, id3v2
** methods : getTags( file.[ogg|mp3] ),
** convertToid3v2( file.[ogg|mp3] ),
** tag( field , newvalue , file.mp3 , [format)
*/
class ClassTags {
public $status, $file, $result;
public $tag = array();
public $taggableF = array(); // formats we can tag
// the three functions following are only about grabbing the tags
function __construct(){
$this->taggableF = array('mp3');
}
public function getTags($arg){
if(!is_file($arg)){
$this->status = 'NoFile';
return;
}
$this->file = escapeshellarg($arg);
$this->result = shell_exec('tagtool --dump '.$this->file);
// for avoid to create a notice error when one of these fields is empty and we try to access it
$this->tag['title'] = ''; $this->tag['artist'] = '';
$this->tag['album'] = ''; $this->tag['year'] = '';
if(shell_exec('file -ib '.$this->file) == "application/ogg\n")
$this->status = $this->getVorbis($this->result);
else { // if it isn't an ogg, we assumes that's mp3
$this->result = utf8_decode($this->result);
if(substr_count($this->result,'---- ID3 v2 ----')
&& preg_match("/ID3 v2 ----\n(.*)/s",$this->result,$matches))
$this->status = $this->getId3($matches[1]);
elseif(substr_count($this->result,'---- ID3 v1 ----')
&& preg_match("/ID3 v1 ----\n(.*)/s",$this->result,$matches)){
$this->status = $this->getId3($matches[1]);
// doesn't deserve anything now, but we know that id3v2 is cooler than id3v1 :)
$this->convertToid3v2($this->file);
} elseif(substr_count($this->result,'No ID3 tags.'))
$this->status = 'NoTags';
else
$this->status = 'UnknowErr';
}
}
private function getId3($str){
if(preg_match("/^TIT2 [^\n]*?\n\s+(.*)$/m",$str,$temp))
$this->tag['title'] = $temp[1];
if(preg_match("/^TPE1 [^\n]*?\n\s+(.*)$/m",$str,$temp))
$this->tag['artist'] = $temp[1];
if(preg_match("/^TALB [^\n]*?\n\s+(.*)$/m",$str,$temp))
$this->tag['album'] = $temp[1];
if(preg_match("/^TYER [^\n]*?\n\s+(.*)$/m",$str,$temp))
$this->tag['year'] = $temp[1];
if(preg_match("/^TRCK [^\n]*?\n\s+(\d+)\/.*$/m",$str,$temp))
$this->tag['track'] = $temp[1];
return true;
}
private function getVorbis($str){
if(preg_match("/^TITLE=([^\n]*)$/m",$str,$temp))
$this->tag['title'] = $temp[1];
if(preg_match("/^ARTIST=([^\n]*)$/m",$str,$temp))
$this->tag['artist'] = $temp[1];
if(preg_match("/^ALBUM=([^\n]*)$/m",$str,$temp))
$this->tag['album'] = $temp[1];
if(preg_match("/^DATE=([^\n]*)$/m",$str,$temp))
$this->tag['year'] = $temp[1];
// as you can see, it's not really the year, but we'll use that name in
return true;
}
// it can be (?? don't remember why i wrote this)
public function convertToid3v2($arg){ // assumes that's a valid mp3 file with NO id3v2 tags AND id3v1 ones
if(preg_match("/\.\.\. converted\n/",shell_exec('id3v2 --convert '.$this->file)))
return true;
else
return 'UnknowErr';
}
// set tags
public function tag($field,$value,$file,$format='mp3'){ // field ISN'T protected
$escval = escapeshellarg($value);
$file = escapeshellarg($file);
if($format == 'mp3'){ // we tag only in id3v2
if(preg_match("/^(album|year|artist|comment)$/",$field))
$opt = $field;
elseif($field == 'title')
$opt = 'song';
shell_exec("id3v2 --$opt $escval $file");
}
}
}
?>
Vous aurez remarqué qu'il n'y a rien pour éditer les tags vorbis (je n'ai que très peu cherché en vérité) et que oui, j'utilise un plugin kisenbon.
Donc le tout s'utilise comme ceci :
$file = 'Natsukawa Rimi - SINGLE COLLECTION Vol.1 (Album)/12 famureuta ( komoriuta ).mp3';
// pour le get
$tagg = new ClassTags;
$tagg->getTags($file);
// et vlan, on peut faire un var_dump($leson) pour constater que l'on a accès à $leson->tag['artist'], etc...
// pour le put
$tagg->tag('title','ふぁむれうた(こもりうた)',$file);
$tagg->tag('artist','夏川りみ',$file);
Vous noterez que id3v1 qui ne supporte pas l'unicode va crier à la mort, tout comme geshi, mais tant pis pour lui, vu que l'on taggue id3v2 aussi.