1<?php
2
3/////////////////////////////////////////////////////////////////
4/// getID3() by James Heinrich <info@getid3.org>               //
5//  available at https://github.com/JamesHeinrich/getID3       //
6//            or https://www.getid3.org                        //
7//            or http://getid3.sourceforge.net                 //
8/////////////////////////////////////////////////////////////////
9//  see readme.txt for more details                            //
10/////////////////////////////////////////////////////////////////
11//                                                             //
12// write.vorbiscomment.php                                     //
13// module for writing VorbisComment tags                       //
14// dependencies: /helperapps/vorbiscomment.exe                 //
15//                                                            ///
16/////////////////////////////////////////////////////////////////
17
18
19class getid3_write_vorbiscomment
20{
21	/**
22	 * @var string
23	 */
24	public $filename;
25
26	/**
27	 * @var array
28	 */
29	public $tag_data;
30
31	/**
32	 * Any non-critical errors will be stored here.
33	 *
34	 * @var array
35	 */
36	public $warnings = array();
37
38	/**
39	 * Any critical errors will be stored here.
40	 *
41	 * @var array
42	 */
43	public $errors   = array();
44
45	public function __construct() {
46	}
47
48	/**
49	 * @return bool
50	 */
51	public function WriteVorbisComment() {
52
53		if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
54			$this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written';
55			return false;
56		}
57
58		// Create file with new comments
59		$tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3');
60		if (getID3::is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) {
61
62			foreach ($this->tag_data as $key => $value) {
63				foreach ($value as $commentdata) {
64					fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n");
65				}
66			}
67			fclose($fpcomments);
68
69		} else {
70			$this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written';
71			return false;
72		}
73
74		$oldignoreuserabort = ignore_user_abort(true);
75		if (GETID3_OS_ISWINDOWS) {
76
77			if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
78				//$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"';
79				//  vorbiscomment works fine if you copy-paste the above commandline into a command prompt,
80				//  but refuses to work with `backtick` if there are "doublequotes" present around BOTH
81				//  the metaflac pathname and the target filename. For whatever reason...??
82				//  The solution is simply ensure that the metaflac pathname has no spaces,
83				//  and therefore does not need to be quoted
84
85				// On top of that, if error messages are not always captured properly under Windows
86				// To at least see if there was a problem, compare file modification timestamps before and after writing
87				clearstatcache();
88				$timestampbeforewriting = filemtime($this->filename);
89
90				$commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
91				$VorbiscommentError = `$commandline`;
92
93				if (empty($VorbiscommentError)) {
94					clearstatcache();
95					if ($timestampbeforewriting == filemtime($this->filename)) {
96						$VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written';
97					}
98				}
99			} else {
100				$VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
101			}
102
103		} else {
104
105			$commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1';
106			$VorbiscommentError = `$commandline`;
107
108		}
109
110		// Remove temporary comments file
111		unlink($tempcommentsfilename);
112		ignore_user_abort($oldignoreuserabort);
113
114		if (!empty($VorbiscommentError)) {
115
116			$this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError;
117			return false;
118
119		}
120
121		return true;
122	}
123
124	/**
125	 * @return bool
126	 */
127	public function DeleteVorbisComment() {
128		$this->tag_data = array(array());
129		return $this->WriteVorbisComment();
130	}
131
132	/**
133	 * @param string $originalcommentname
134	 *
135	 * @return string
136	 */
137	public function CleanVorbisCommentName($originalcommentname) {
138		// A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded.
139		// ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through
140		// 0x7A inclusive (a-z).
141
142		// replace invalid chars with a space, return uppercase text
143		// Thanks Chris Bolt <chris-getid3Øbolt*cx> for improving this function
144		// note: *reg_replace() replaces nulls with empty string (not space)
145		return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname)));
146
147	}
148
149}
150