1<?php
2/////////////////////////////////////////////////////////////////
3/// getID3() by James Heinrich <info@getid3.org>               //
4//  available at https://github.com/JamesHeinrich/getID3       //
5//            or https://www.getid3.org                        //
6//            or http://getid3.sourceforge.net                 //
7//                                                             //
8// /demo/demo.browse.php - part of getID3()                    //
9// Sample script for browsing/scanning files and displaying    //
10// information returned by getID3()                            //
11//  see readme.txt for more details                            //
12//                                                            ///
13/////////////////////////////////////////////////////////////////
14
15die('For security reasons, this demo has been disabled. It can be enabled by removing line '.__LINE__.' in demos/'.basename(__FILE__));
16
17
18define('GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK',   false); // if enabled, shows "edit" links (to /demos/demo.write.php) to allow ID3/APE/etc tag editing on applicable file types
19define('GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK', false); // if enabled, shows "delete" links to delete files from the browse interface
20define('GETID3_DEMO_BROWSE_ALLOW_MD5_LINK',    false); // if enabled, shows "enable" link for MD5 hashes for file/data/source
21
22/////////////////////////////////////////////////////////////////
23// die if magic_quotes_runtime or magic_quotes_gpc are set
24if (version_compare(PHP_VERSION, '7.4.0', '<')) { // get_magic_quotes_runtime / get_magic_quotes_gpc functions give deprecation warnings in PHP v7.4
25	if (function_exists('get_magic_quotes_runtime') && get_magic_quotes_runtime()) {
26		die('magic_quotes_runtime is enabled, getID3 will not run.');
27	}
28	if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
29		die('magic_quotes_gpc is enabled, getID3 will not run.');
30	}
31}
32/////////////////////////////////////////////////////////////////
33
34require_once('../getid3/getid3.php');
35
36$PageEncoding       = 'UTF-8';
37$FileSystemEncoding = ((GETID3_OS_ISWINDOWS && version_compare(PHP_VERSION, '7.1.0', '<')) ? 'Windows-1252' : 'UTF-8');
38$writescriptfilename = 'demo.write.php';
39
40// Needed for windows only. Leave commented-out to auto-detect, only define here if auto-detection does not work properly
41//define('GETID3_HELPERAPPSDIR', 'C:\\helperapps\\');
42
43// Initialize getID3 engine
44$getID3 = new getID3;
45$getID3->setOption(array('encoding' => $PageEncoding));
46
47$getID3checkColor_Head           = 'CCCCDD';
48$getID3checkColor_DirectoryLight = 'FFCCCC';
49$getID3checkColor_DirectoryDark  = 'EEBBBB';
50$getID3checkColor_FileLight      = 'EEEEEE';
51$getID3checkColor_FileDark       = 'DDDDDD';
52$getID3checkColor_UnknownLight   = 'CCCCFF';
53$getID3checkColor_UnknownDark    = 'BBBBDD';
54
55
56///////////////////////////////////////////////////////////////////////////////
57
58
59header('Content-Type: text/html; charset='.$PageEncoding);
60echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
61echo '<html><head>';
62echo '<title>getID3() - /demo/demo.browse.php (sample script)</title>';
63echo '<link rel="stylesheet" href="getid3.css" type="text/css">';
64echo '<meta http-equiv="Content-Type" content="text/html;charset='.$PageEncoding.'" />';
65echo '</head><body>';
66
67if (isset($_REQUEST['deletefile']) && GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK) {
68	if (file_exists($_REQUEST['deletefile'])) {
69		if (unlink($_REQUEST['deletefile'])) {
70			$deletefilemessage = 'Successfully deleted '.$_REQUEST['deletefile'];
71		} else {
72			$deletefilemessage = 'FAILED to delete '.$_REQUEST['deletefile'].' - error deleting file';
73		}
74	} else {
75		$deletefilemessage = 'FAILED to delete '.$_REQUEST['deletefile'].' - file does not exist';
76	}
77	if (isset($_REQUEST['noalert'])) {
78		echo '<span style="font-weight: bold; color: #'.(($deletefilemessage[0] == 'F') ? 'FF0000' : '008000').';">'.htmlentities($deletefilemessage, ENT_QUOTES).'</span><hr>';
79	} else {
80		echo '<script type="text/javascript">alert("'.addslashes($deletefilemessage).'");</script>';
81	}
82}
83
84
85if (isset($_REQUEST['filename'])) {
86
87	if (!file_exists($_REQUEST['filename']) || !is_file($_REQUEST['filename'])) {
88		die(getid3_lib::iconv_fallback($FileSystemEncoding, $PageEncoding, $_REQUEST['filename'].' does not exist'));
89	}
90	$starttime = microtime(true);
91
92	//$getID3->setOption(array(
93	//	'option_md5_data'  => $AutoGetHashes,
94	//	'option_sha1_data' => $AutoGetHashes,
95	//));
96	$ThisFileInfo = $getID3->analyze($_REQUEST['filename']);
97	$AutoGetHashes = (bool) (isset($ThisFileInfo['filesize']) && ($ThisFileInfo['filesize'] > 0) && ($ThisFileInfo['filesize'] < (50 * 1048576))); // auto-get md5_data, md5_file, sha1_data, sha1_file if filesize < 50MB, and NOT zero (which may indicate a file>2GB)
98	$AutoGetHashes = ($AutoGetHashes && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK);
99	if ($AutoGetHashes) {
100		$ThisFileInfo['md5_file']  = md5_file($_REQUEST['filename']);
101		$ThisFileInfo['sha1_file'] = sha1_file($_REQUEST['filename']);
102	}
103
104
105	$getID3->CopyTagsToComments($ThisFileInfo);
106
107	$listdirectory = dirname($_REQUEST['filename']);
108	$listdirectory = realpath($listdirectory); // get rid of /../../ references
109
110	if (GETID3_OS_ISWINDOWS) {
111		// this mostly just gives a consistant look to Windows and *nix filesystems
112		// (windows uses \ as directory seperator, *nix uses /)
113		$listdirectory = str_replace(DIRECTORY_SEPARATOR, '/', $listdirectory.'/');
114	}
115
116	if (preg_match('#^(ht|f)tp://#', $_REQUEST['filename'])) {
117		echo '<i>Cannot browse remote filesystems</i><br>';
118	} else {
119		echo 'Browse: <a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($listdirectory), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">'.getid3_lib::iconv_fallback($FileSystemEncoding, $PageEncoding, $listdirectory).'</a><br>';
120	}
121
122	getid3_lib::ksort_recursive($ThisFileInfo);
123	echo table_var_dump($ThisFileInfo, false, $PageEncoding);
124	$endtime = microtime(true);
125	echo 'File parsed in '.number_format($endtime - $starttime, 3).' seconds.<br>';
126
127} else {
128
129	$listdirectory = (isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.');
130	$listdirectory = getid3_lib::truepath($listdirectory); // get rid of /../../ references
131	$currentfulldir = str_replace(DIRECTORY_SEPARATOR, '/', $listdirectory).'/'; // this mostly just gives a consistant look to Windows and *nix filesystems: (Windows uses \ as directory seperator, *nix uses /)
132
133	ob_start();
134	if ($handle = opendir($listdirectory)) {
135
136		ob_end_clean();
137		echo str_repeat(' ', 300); // IE buffers the first 300 or so chars, making this progressive display useless - fill the buffer with spaces
138		echo 'Processing';
139
140		$starttime = microtime(true);
141
142		$TotalScannedUnknownFiles  = 0;
143		$TotalScannedKnownFiles    = 0;
144		$TotalScannedPlaytimeFiles = 0;
145		$TotalScannedBitrateFiles  = 0;
146		$TotalScannedFilesize      = 0;
147		$TotalScannedPlaytime      = 0;
148		$TotalScannedBitrate       = 0;
149		$FilesWithWarnings         = 0;
150		$FilesWithErrors           = 0;
151
152		while ($file = readdir($handle)) {
153			$currentfilename = $listdirectory.'/'.$file;
154			set_time_limit(30); // allocate another 30 seconds to process this file - should go much quicker than this unless intense processing (like bitrate histogram analysis) is enabled
155			echo ' <span title="'.htmlentities($file, ENT_QUOTES).'">.</span>'; // progress indicator dot
156			flush();  // make sure the dot is shown, otherwise it's useless
157			switch ($file) {
158				case '..':
159					$ParentDir = realpath($file.'/..').'/';
160					if (GETID3_OS_ISWINDOWS) {
161						$ParentDir = str_replace(DIRECTORY_SEPARATOR, '/', $ParentDir);
162					}
163					$DirectoryContents[$currentfulldir]['dir'][$file]['filename'] = $ParentDir;
164					continue 2;
165					break;
166
167				case '.':
168					// ignore
169					continue 2;
170					break;
171			}
172			// symbolic-link-resolution enhancements by davidbullock״ech-center*com
173			$TargetObject     = realpath($currentfilename);  // Find actual file path, resolve if it's a symbolic link
174			$TargetObjectType = filetype($TargetObject);     // Check file type without examining extension
175
176			if ($TargetObjectType == 'dir') {
177
178				$DirectoryContents[$currentfulldir]['dir'][$file]['filename'] = $file;
179
180			} elseif ($TargetObjectType == 'file') {
181
182				$getID3->setOption(array('option_md5_data' => (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK)));
183				$fileinformation = $getID3->analyze($currentfilename);
184
185				$getID3->CopyTagsToComments($fileinformation);
186
187				$TotalScannedFilesize += (isset($fileinformation['filesize']) ? $fileinformation['filesize'] : 0);
188
189				if (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK) {
190					$fileinformation['md5_file'] = md5_file($currentfilename);
191				}
192
193				if (!empty($fileinformation['fileformat'])) {
194					$DirectoryContents[$currentfulldir]['known'][$file] = $fileinformation;
195					$TotalScannedPlaytime += (isset($fileinformation['playtime_seconds']) ? $fileinformation['playtime_seconds'] : 0);
196					$TotalScannedBitrate  += (isset($fileinformation['bitrate'])          ? $fileinformation['bitrate']          : 0);
197					$TotalScannedKnownFiles++;
198				} else {
199					$DirectoryContents[$currentfulldir]['other'][$file] = $fileinformation;
200					$DirectoryContents[$currentfulldir]['other'][$file]['playtime_string'] = '-';
201					$TotalScannedUnknownFiles++;
202				}
203				if (isset($fileinformation['playtime_seconds']) && ($fileinformation['playtime_seconds'] > 0)) {
204					$TotalScannedPlaytimeFiles++;
205				}
206				if (isset($fileinformation['bitrate']) && ($fileinformation['bitrate'] > 0)) {
207					$TotalScannedBitrateFiles++;
208				}
209
210			} else {
211
212				echo '<div style="color: red;">Unknown filesystem entry: "'.htmlentities($currentfilename, ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'"</div>';
213
214			}
215		}
216		$endtime = microtime(true);
217		closedir($handle);
218		echo 'done<br>';
219		echo 'Directory scanned in '.number_format($endtime - $starttime, 2).' seconds.<br>';
220		flush();
221
222		$columnsintable = 14;
223		echo '<table class="table" cellspacing="0" cellpadding="3">';
224
225		echo '<tr bgcolor="#'.$getID3checkColor_Head.'"><th colspan="'.$columnsintable.'">Files in '.getid3_lib::iconv_fallback($FileSystemEncoding, $PageEncoding, $currentfulldir).'</th></tr>';
226		$rowcounter = 0;
227		foreach ($DirectoryContents as $dirname => $val) {
228			if (isset($DirectoryContents[$dirname]['dir']) && is_array($DirectoryContents[$dirname]['dir'])) {
229				uksort($DirectoryContents[$dirname]['dir'], 'MoreNaturalSort');
230				foreach ($DirectoryContents[$dirname]['dir'] as $filename => $fileinfo) {
231					echo '<tr bgcolor="#'.(($rowcounter++ % 2) ? $getID3checkColor_DirectoryLight : $getID3checkColor_DirectoryDark).'">';
232					if ($filename == '..') {
233						echo '<td colspan="'.$columnsintable.'">';
234						echo '<form action="'.htmlentities($_SERVER['PHP_SELF'], ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" method="get">';
235						echo 'Parent directory: ';
236						echo '<input type="text" name="listdirectory" size="50" style="background-color: '.$getID3checkColor_DirectoryDark.';" value="';
237						if (GETID3_OS_ISWINDOWS) {
238							echo htmlentities(str_replace(DIRECTORY_SEPARATOR, '/', realpath($dirname.$filename)), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding);
239						} else {
240							echo htmlentities(realpath($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding);
241						}
242						echo '"> <input type="submit" value="Go">';
243						echo '</form></td>';
244					} else {
245						$escaped_filename = htmlentities($filename, ENT_SUBSTITUTE, $FileSystemEncoding); // do filesystems always return filenames in ISO-8859-1?
246						$escaped_filename = ($escaped_filename ? $escaped_filename : rawurlencode($filename));
247						echo '<td colspan="'.$columnsintable.'"><a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'"><b>'.$escaped_filename.'</b></a></td>';
248					}
249					echo '</tr>';
250				}
251			}
252
253			echo '<tr bgcolor="#'.$getID3checkColor_Head.'">';
254			echo '<th>Filename</th>';
255			echo '<th>File Size</th>';
256			echo '<th>Format</th>';
257			echo '<th>Playtime</th>';
258			echo '<th>Bitrate</th>';
259			echo '<th>Artist</th>';
260			echo '<th>Title</th>';
261			if (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK) {
262				echo '<th>MD5&nbsp;File (File) (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.'), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">disable</a>)</th>';
263				echo '<th>MD5&nbsp;Data (File) (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.'), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">disable</a>)</th>';
264				echo '<th>MD5&nbsp;Data (Source) (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.'), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">disable</a>)</th>';
265			} else {
266				echo '<th colspan="3">MD5&nbsp;Data'.(GETID3_DEMO_BROWSE_ALLOW_MD5_LINK ?' (<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.rawurlencode(isset($_REQUEST['listdirectory']) ? $_REQUEST['listdirectory'] : '.').'&ShowMD5=1', ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">enable</a>)' : '').'</th>';
267			}
268			echo '<th>Tags</th>';
269			echo '<th>Errors &amp; Warnings</th>';
270			echo (GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK   ? '<th>Edit</th>'   : '');
271			echo (GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK ? '<th>Delete</th>' : '');
272			echo '</tr>';
273
274			if (isset($DirectoryContents[$dirname]['known']) && is_array($DirectoryContents[$dirname]['known'])) {
275				uksort($DirectoryContents[$dirname]['known'], 'MoreNaturalSort');
276				foreach ($DirectoryContents[$dirname]['known'] as $filename => $fileinfo) {
277					echo '<tr bgcolor="#'.(($rowcounter++ % 2) ? $getID3checkColor_FileDark : $getID3checkColor_FileLight).'">';
278					$escaped_filename = htmlentities($filename, ENT_SUBSTITUTE, $FileSystemEncoding); // do filesystems always return filenames in ISO-8859-1?
279					$escaped_filename = ($escaped_filename ? $escaped_filename : rawurlencode($filename));
280					echo '<td><a href="'.htmlentities($_SERVER['PHP_SELF'].'?filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" title="View detailed analysis">'.$escaped_filename.'</a></td>';
281					echo '<td align="right">&nbsp;'.number_format($fileinfo['filesize']).'</td>';
282					echo '<td align="right">&nbsp;'.NiceDisplayFiletypeFormat($fileinfo).'</td>';
283					echo '<td align="right">&nbsp;'.(isset($fileinfo['playtime_string']) ? $fileinfo['playtime_string'] : '-').'</td>';
284					echo '<td align="right">&nbsp;'.(isset($fileinfo['bitrate']) ? BitrateText($fileinfo['bitrate'] / 1000, 0, ((isset($fileinfo['audio']['bitrate_mode']) && ($fileinfo['audio']['bitrate_mode'] == 'vbr')) ? true : false)) : '-').'</td>';
285					echo '<td align="left">&nbsp;'.(isset($fileinfo['comments_html']['artist']) ? implode('<br>', $fileinfo['comments_html']['artist']) : ((isset($fileinfo['video']['resolution_x']) && isset($fileinfo['video']['resolution_y'])) ? $fileinfo['video']['resolution_x'].'x'.$fileinfo['video']['resolution_y'] : '')).'</td>';
286					echo '<td align="left">&nbsp;'.(isset($fileinfo['comments_html']['title'])  ? implode('<br>', $fileinfo['comments_html']['title'])  :  (isset($fileinfo['video']['frame_rate'])                                                 ? number_format($fileinfo['video']['frame_rate'], 3).'fps'                  : '')).'</td>';
287					if (isset($_REQUEST['ShowMD5']) && GETID3_DEMO_BROWSE_ALLOW_MD5_LINK) {
288						echo '<td align="left"><tt>'.(isset($fileinfo['md5_file'])        ? $fileinfo['md5_file']        : '&nbsp;').'</tt></td>';
289						echo '<td align="left"><tt>'.(isset($fileinfo['md5_data'])        ? $fileinfo['md5_data']        : '&nbsp;').'</tt></td>';
290						echo '<td align="left"><tt>'.(isset($fileinfo['md5_data_source']) ? $fileinfo['md5_data_source'] : '&nbsp;').'</tt></td>';
291					} else {
292						echo '<td align="center" colspan="3">-</td>';
293					}
294					echo '<td align="left">&nbsp;'.(!empty($fileinfo['tags']) ? implode(', ', array_keys($fileinfo['tags'])) : '').'</td>';
295
296					echo '<td align="left">&nbsp;';
297					if (!empty($fileinfo['warning'])) {
298						$FilesWithWarnings++;
299						echo '<a href="#" onClick="alert(\''.htmlentities(str_replace("'", "\\'", preg_replace('#[\r\n\t]+#', ' ', implode('\\n', $fileinfo['warning']))), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("; \n", $fileinfo['warning']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">warning</a><br>';
300					}
301					if (!empty($fileinfo['error'])) {
302						$FilesWithErrors++;
303						echo '<a href="#" onClick="alert(\''.htmlentities(str_replace("'", "\\'", preg_replace('#[\r\n\t]+#', ' ', implode('\\n', $fileinfo['error']))),   ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("; \n", $fileinfo['error']),   ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">error</a><br>';
304					}
305					echo '</td>';
306
307					if (GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK) {
308						echo '<td align="left">&nbsp;';
309						$fileinfo['fileformat'] = (isset($fileinfo['fileformat']) ? $fileinfo['fileformat'] : '');
310						switch ($fileinfo['fileformat']) {
311							case 'mp3':
312							case 'mp2':
313							case 'mp1':
314							case 'flac':
315							case 'mpc':
316							case 'real':
317								echo '<a href="'.htmlentities($writescriptfilename.'?Filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" title="Edit tags">edit&nbsp;tags</a>';
318								break;
319							case 'ogg':
320								if (isset($fileinfo['audio']['dataformat']) && ($fileinfo['audio']['dataformat'] == 'vorbis')) {
321									echo '<a href="'.htmlentities($writescriptfilename.'?Filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" title="Edit tags">edit&nbsp;tags</a>';
322								}
323								break;
324							default:
325								break;
326						}
327						echo '</td>';
328					}
329					if (GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK) {
330						echo '<td align="left">&nbsp;<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($listdirectory).'&deletefile='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" onClick="return confirm(\'Are you sure you want to delete '.addslashes(htmlentities($dirname.$filename)).'? \n(this action cannot be un-done)\');" title="'.htmlentities('Permanently delete '."\n".$filename."\n".' from'."\n".' '.$dirname, ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">delete</a></td>';
331					}
332					echo '</tr>';
333				}
334			}
335
336			if (isset($DirectoryContents[$dirname]['other']) && is_array($DirectoryContents[$dirname]['other'])) {
337				uksort($DirectoryContents[$dirname]['other'], 'MoreNaturalSort');
338				foreach ($DirectoryContents[$dirname]['other'] as $filename => $fileinfo) {
339					echo '<tr bgcolor="#'.(($rowcounter++ % 2) ? $getID3checkColor_UnknownDark : $getID3checkColor_UnknownLight).'">';
340					$escaped_filename = htmlentities($filename, ENT_SUBSTITUTE, $PageEncoding);
341					$escaped_filename = ($escaped_filename ? $escaped_filename : rawurlencode($filename));
342					echo '<td><a href="'.htmlentities($_SERVER['PHP_SELF'].'?filename='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'"><i>'.$escaped_filename.'</i></a></td>';
343					echo '<td align="right">&nbsp;'.(isset($fileinfo['filesize']) ? number_format($fileinfo['filesize']) : '-').'</td>';
344					echo '<td align="right">&nbsp;'.NiceDisplayFiletypeFormat($fileinfo).'</td>';
345					echo '<td align="right">&nbsp;'.(isset($fileinfo['playtime_string']) ? $fileinfo['playtime_string'] : '-').'</td>';
346					echo '<td align="right">&nbsp;'.(isset($fileinfo['bitrate']) ? BitrateText($fileinfo['bitrate'] / 1000) : '-').'</td>';
347					echo '<td align="left">&nbsp;</td>'; // Artist
348					echo '<td align="left">&nbsp;</td>'; // Title
349					echo '<td align="left" colspan="3">&nbsp;</td>'; // MD5_data
350					echo '<td align="left">&nbsp;</td>'; // Tags
351
352					//echo '<td align="left">&nbsp;</td>'; // Warning/Error
353					echo '<td align="left">&nbsp;';
354					if (!empty($fileinfo['warning'])) {
355						$FilesWithWarnings++;
356						echo '<a href="#" onClick="alert(\''.htmlentities(implode('\\n', $fileinfo['warning']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("\n", $fileinfo['warning']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">warning</a><br>';
357					}
358					if (!empty($fileinfo['error'])) {
359						if ($fileinfo['error'][0] != 'unable to determine file format') {
360							$FilesWithErrors++;
361							echo '<a href="#" onClick="alert(\''.htmlentities(implode('\\n', $fileinfo['error']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'\'); return false;" title="'.htmlentities(implode("\n", $fileinfo['error']), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'">error</a><br>';
362						}
363					}
364					echo '</td>';
365
366					if (GETID3_DEMO_BROWSE_ALLOW_EDIT_LINK) {
367						echo '<td align="left">&nbsp;</td>'; // Edit
368					}
369					if (GETID3_DEMO_BROWSE_ALLOW_DELETE_LINK) {
370						echo '<td align="left">&nbsp;<a href="'.htmlentities($_SERVER['PHP_SELF'].'?listdirectory='.urlencode($listdirectory).'&deletefile='.urlencode($dirname.$filename), ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'" onClick="return confirm(\'Are you sure you want to delete '.addslashes($dirname.$filename).'? \n(this action cannot be un-done)\');" title="Permanently delete '.addslashes($dirname.$filename).'">delete</a></td>';
371					}
372					echo '</tr>';
373				}
374			}
375
376			echo '<tr bgcolor="#'.$getID3checkColor_Head.'">';
377			echo '<td><b>Average:</b></td>';
378			echo '<td align="right">'.number_format($TotalScannedFilesize / max($TotalScannedKnownFiles, 1)).'</td>';
379			echo '<td>&nbsp;</td>';
380			echo '<td align="right">'.getid3_lib::PlaytimeString($TotalScannedPlaytime / max($TotalScannedPlaytimeFiles, 1)).'</td>';
381			echo '<td align="right">'.BitrateText(round(($TotalScannedBitrate / 1000) / max($TotalScannedBitrateFiles, 1))).'</td>';
382			echo '<td rowspan="2" colspan="'.($columnsintable - 5).'"><table class="table" border="0" cellspacing="0" cellpadding="2"><tr><th align="right">Identified Files:</th><td align="right">'.number_format($TotalScannedKnownFiles).'</td><td>&nbsp;&nbsp;&nbsp;</td><th align="right">Errors:</th><td align="right">'.number_format($FilesWithErrors).'</td></tr><tr><th align="right">Unknown Files:</th><td align="right">'.number_format($TotalScannedUnknownFiles).'</td><td>&nbsp;&nbsp;&nbsp;</td><th align="right">Warnings:</th><td align="right">'.number_format($FilesWithWarnings).'</td></tr></table>';
383			echo '</tr>';
384			echo '<tr bgcolor="#'.$getID3checkColor_Head.'">';
385			echo '<td><b>Total:</b></td>';
386			echo '<td align="right">'.number_format($TotalScannedFilesize).'</td>';
387			echo '<td>&nbsp;</td>';
388			echo '<td align="right">'.getid3_lib::PlaytimeString($TotalScannedPlaytime).'</td>';
389			echo '<td>&nbsp;</td>';
390			echo '</tr>';
391		}
392		echo '</table>';
393	} else {
394		$errormessage = ob_get_contents();
395		ob_end_clean();
396		echo '<b>ERROR: Could not open directory: <u>'.htmlentities($currentfulldir, ENT_QUOTES | ENT_SUBSTITUTE, $PageEncoding).'</u></b><br>';
397		//echo $errormessage.'<br>'; // uncomment for debugging
398	}
399}
400echo PoweredBygetID3().'<br clear="all">';
401echo '</body></html>';
402
403
404/////////////////////////////////////////////////////////////////
405
406
407function RemoveAccents($string) {
408	// Revised version by markstewardרotmail*com
409	// Again revised by James Heinrich (19-June-2006)
410	return strtr(
411		strtr(
412			$string,
413			"\x8A\x8E\x9A\x9E\x9F\xC0\xC1\xC2\xC3\xC4\xC5\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD1\xD2\xD3\xD4\xD5\xD6\xD8\xD9\xDA\xDB\xDC\xDD\xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF1\xF2\xF3\xF4\xF5\xF6\xF8\xF9\xFA\xFB\xFC\xFD\xFF",
414			'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'
415		),
416		array(
417			"\xDE" => 'TH',
418			"\xFE" => 'th',
419			"\xD0" => 'DH',
420			"\xF0" => 'dh',
421			"\xDF" => 'ss',
422			"\x8C" => 'OE',
423			"\x9C" => 'oe',
424			"\xC6" => 'AE',
425			"\xE6" => 'ae',
426			"\xB5" => 'u'
427		)
428	);
429}
430
431
432function BitrateColor($bitrate, $BitrateMaxScale=768) {
433	// $BitrateMaxScale is bitrate of maximum-quality color (bright green)
434	// below this is gradient, above is solid green
435
436	$bitrate *= (256 / $BitrateMaxScale); // scale from 1-[768]kbps to 1-256
437	$bitrate = round(min(max($bitrate, 1), 256));
438	$bitrate--;    // scale from 1-256kbps to 0-255kbps
439
440	$Rcomponent = max(255 - ($bitrate * 2), 0);
441	$Gcomponent = max(($bitrate * 2) - 255, 0);
442	if ($bitrate > 127) {
443		$Bcomponent = max((255 - $bitrate) * 2, 0);
444	} else {
445		$Bcomponent = max($bitrate * 2, 0);
446	}
447	return str_pad(dechex($Rcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Gcomponent), 2, '0', STR_PAD_LEFT).str_pad(dechex($Bcomponent), 2, '0', STR_PAD_LEFT);
448}
449
450function BitrateText($bitrate, $decimals=0, $vbr=false) {
451	return '<span style="color: #'.BitrateColor($bitrate).($vbr ? '; font-weight: bold;' : '').'">'.number_format($bitrate, $decimals).' kbps</span>';
452}
453
454function string_var_dump($variable) {
455	if (version_compare(PHP_VERSION, '4.3.0', '>=')) {
456		return print_r($variable, true);
457	}
458	ob_start();
459	var_dump($variable);
460	$dumpedvariable = ob_get_contents();
461	ob_end_clean();
462	return $dumpedvariable;
463}
464
465function table_var_dump($variable, $wrap_in_td=false, $encoding='') {
466	global $FileSystemEncoding;
467	$encoding = ($encoding ? $encoding : $FileSystemEncoding);
468	$returnstring = '';
469	switch (gettype($variable)) {
470		case 'array':
471			$returnstring .= ($wrap_in_td ? '<td>' : '');
472			$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
473			foreach ($variable as $key => $value) {
474				$returnstring .= '<tr><td valign="top"><b>'.str_replace("\x00", ' ', $key).'</b></td>'."\n";
475				$returnstring .= '<td valign="top">'.gettype($value);
476				if (is_array($value)) {
477					$returnstring .= '&nbsp;('.count($value).')';
478				} elseif (is_string($value)) {
479					$returnstring .= '&nbsp;('.strlen($value).')';
480				}
481				//if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset'])) {
482				if (($key == 'data') && isset($variable['image_mime'])) {
483					$imageinfo = array();
484					if ($imagechunkcheck = getid3_lib::GetDataImageSize($value, $imageinfo)) {
485						$returnstring .= '</td>'."\n".'<td><img src="data:'.$variable['image_mime'].';base64,'.base64_encode($value).'" width="'.$imagechunkcheck[0].'" height="'.$imagechunkcheck[1].'"></td></tr>'."\n";
486					} else {
487						$returnstring .= '</td>'."\n".'<td><i>invalid image data</i></td></tr>'."\n";
488					}
489				} else {
490					$returnstring .= '</td>'."\n".table_var_dump($value, true, $encoding).'</tr>'."\n";
491				}
492			}
493			$returnstring .= '</table>'."\n";
494			$returnstring .= ($wrap_in_td ? '</td>'."\n" : '');
495			break;
496
497		case 'boolean':
498			$returnstring .= ($wrap_in_td ? '<td class="dump_boolean">' : '').($variable ? 'TRUE' : 'FALSE').($wrap_in_td ? '</td>'."\n" : '');
499			break;
500
501		case 'integer':
502			$returnstring .= ($wrap_in_td ? '<td class="dump_integer">' : '').$variable.($wrap_in_td ? '</td>'."\n" : '');
503			break;
504
505		case 'double':
506		case 'float':
507			$returnstring .= ($wrap_in_td ? '<td class="dump_double">' : '').$variable.($wrap_in_td ? '</td>'."\n" : '');
508			break;
509
510		case 'object':
511		case 'null':
512			$returnstring .= ($wrap_in_td ? '<td>' : '').string_var_dump($variable).($wrap_in_td ? '</td>'."\n" : '');
513			break;
514
515		case 'string':
516			$returnstring = htmlentities($variable, ENT_QUOTES | ENT_SUBSTITUTE, $encoding);
517			$returnstring = ($wrap_in_td ? '<td class="dump_string">' : '').nl2br($returnstring).($wrap_in_td ? '</td>'."\n" : '');
518			break;
519
520		default:
521			$imageinfo = array();
522			if (($imagechunkcheck = getid3_lib::GetDataImageSize($variable, $imageinfo)) && ($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
523				$returnstring .= ($wrap_in_td ? '<td>' : '');
524				$returnstring .= '<table class="dump" cellspacing="0" cellpadding="2">';
525				$returnstring .= '<tr><td><b>type</b></td><td>'.image_type_to_mime_type($imagechunkcheck[2]).'</td></tr>'."\n";
526				$returnstring .= '<tr><td><b>width</b></td><td>'.number_format($imagechunkcheck[0]).' px</td></tr>'."\n";
527				$returnstring .= '<tr><td><b>height</b></td><td>'.number_format($imagechunkcheck[1]).' px</td></tr>'."\n";
528				$returnstring .= '<tr><td><b>size</b></td><td>'.number_format(strlen($variable)).' bytes</td></tr></table>'."\n";
529				$returnstring .= ($wrap_in_td ? '</td>'."\n" : '');
530			} else {
531				$returnstring .= ($wrap_in_td ? '<td>' : '').nl2br(htmlspecialchars(str_replace("\x00", ' ', $variable))).($wrap_in_td ? '</td>'."\n" : '');
532			}
533			break;
534	}
535	return $returnstring;
536}
537
538
539function NiceDisplayFiletypeFormat(&$fileinfo) {
540
541	if (empty($fileinfo['fileformat'])) {
542		return '-';
543	}
544
545	$output  = $fileinfo['fileformat'];
546	if (empty($fileinfo['video']['dataformat']) && empty($fileinfo['audio']['dataformat'])) {
547		return $output;  // 'gif'
548	}
549	if (empty($fileinfo['video']['dataformat']) && !empty($fileinfo['audio']['dataformat'])) {
550		if ($fileinfo['fileformat'] == $fileinfo['audio']['dataformat']) {
551			return $output; // 'mp3'
552		}
553		$output .= '.'.$fileinfo['audio']['dataformat']; // 'ogg.flac'
554		return $output;
555	}
556	if (!empty($fileinfo['video']['dataformat']) && empty($fileinfo['audio']['dataformat'])) {
557		if ($fileinfo['fileformat'] == $fileinfo['video']['dataformat']) {
558			return $output; // 'mpeg'
559		}
560		$output .= '.'.$fileinfo['video']['dataformat']; // 'riff.avi'
561		return $output;
562	}
563	if ($fileinfo['video']['dataformat'] == $fileinfo['audio']['dataformat']) {
564		if ($fileinfo['fileformat'] == $fileinfo['video']['dataformat']) {
565			return $output; // 'real'
566		}
567		$output .= '.'.$fileinfo['video']['dataformat']; // any examples?
568		return $output;
569	}
570	$output .= '.'.$fileinfo['video']['dataformat'];
571	$output .= '.'.$fileinfo['audio']['dataformat']; // asf.wmv.wma
572	return $output;
573
574}
575
576function MoreNaturalSort($ar1, $ar2) {
577	if ($ar1 === $ar2) {
578		return 0;
579	}
580	$len1     = strlen($ar1);
581	$len2     = strlen($ar2);
582	$shortest = min($len1, $len2);
583	if (substr($ar1, 0, $shortest) === substr($ar2, 0, $shortest)) {
584		// the shorter argument is the beginning of the longer one, like "str" and "string"
585		if ($len1 < $len2) {
586			return -1;
587		} elseif ($len1 > $len2) {
588			return 1;
589		}
590		return 0;
591	}
592	$ar1 = RemoveAccents(strtolower(trim($ar1)));
593	$ar2 = RemoveAccents(strtolower(trim($ar2)));
594	$translatearray = array('\''=>'', '"'=>'', '_'=>' ', '('=>'', ')'=>'', '-'=>' ', '  '=>' ', '.'=>'', ','=>'');
595	foreach ($translatearray as $key => $val) {
596		$ar1 = str_replace($key, $val, $ar1);
597		$ar2 = str_replace($key, $val, $ar2);
598	}
599
600	if ($ar1 < $ar2) {
601		return -1;
602	} elseif ($ar1 > $ar2) {
603		return 1;
604	}
605	return 0;
606}
607
608/**
609 * @param string $string
610 *
611 * @return mixed
612 */
613function PoweredBygetID3($string='') {
614	global $getID3;
615	if (!$string) {
616		$string = '<div style="border: 1px #CCCCCC solid; padding: 5px; margin: 5px 0; float: left; background-color: #EEEEEE; font-size: 8pt; font-family: sans-serif;">Powered by <a href="https://www.getid3.org/"><b>getID3() v<!--GETID3VER--></b><br>https://www.getid3.org/</a><br>Running on PHP v'.PHP_VERSION.' ('.(8 * PHP_INT_SIZE).'-bit, '.(defined('PHP_OS_FAMILY') ? PHP_OS_FAMILY : PHP_OS).')</div>';
617	}
618	return str_replace('<!--GETID3VER-->', $getID3->version(), $string);
619}
620