/** * Produce a HTML snippet detailing the given file in the JSON 'content' element; place additional info * in the JSON elements 'thumbnail', 'thumb48', 'thumb250', 'width', 'height', ... * * Return an augmented JSON array. * * Throw an exception on error. */ public function extractDetailInfo($json_in, $legal_url, &$meta, $mime_filter, $mime_filters, $mode) { $auto_thumb_gen_mode = !in_array('direct', $mode, true); $metaHTML_mode = in_array('metaHTML', $mode, true); $metaJSON_mode = in_array('metaJSON', $mode, true); $url = $this->legal2abs_url_path($legal_url); $filename = basename($url); log_message('error', '$url : ' . $url); // must transform here so alias/etc. expansions inside url_path2file_path() get a chance: $file = $this->url_path2file_path($url); $isdir = !is_file($file); $bad_ext = false; $mime = null; // only perform the (costly) getID3 scan when it hasn't been done before, i.e. can we re-use previously obtained data or not? if (!is_object($meta)) { $meta = $this->getFileInfo($file, $legal_url); } if (!$isdir) { $mime = $meta->getMimeType(); $mime2 = $this->getMimeFromExt($file); $meta->store('mime_type from file extension', $mime2); $bad_ext = $mime2 != $mime; if ($bad_ext) { $iconspec = 'is.' + $this->getExtFromMime($mime); } else { $iconspec = $filename; } if (!$this->IsAllowedMimeType($mime, $mime_filters)) { throw new FileManagerException('extension'); } } else { if (is_dir($file)) { $mime = $meta->getMimeType(); // $mime = 'text/directory'; $iconspec = 'is.directory'; } else { // simply do NOT list anything that we cannot cope with. // That includes clearly inaccessible files (and paths) with non-ASCII characters: // PHP5 and below are a real mess when it comes to handling Unicode filesystems // (see the php.net site too: readdir / glob / etc. user comments and the official // notice that PHP will support filesystem UTF-8/Unicode only when PHP6 is released. // // Big, fat bummer! throw new FileManagerException('nofile'); } } // as all the work below is quite costly, we check whether the already loaded cache entry got our number: // several chunks of work below may have been cached and when they have been, use the cached data. // it's an internal error when this entry do not exist in the cache store by now! $fi = $meta->fetch('analysis'); //assert(!empty($fi)); $icon48 = $this->getIcon($iconspec, false); $icon = $this->getIcon($iconspec, true); $thumb250 = $meta->fetch('thumb250_direct'); $thumb48 = $meta->fetch('thumb48_direct'); $thumb250_e = false; $thumb48_e = false; $tstamp_str = date($this->options['dateFormat'], @filemtime($file)); $fsize = @filesize($file); $json = array_merge(array('content' => self::compressHTML('<div class="margin"> ${nopreview} </div>')), array('path' => $legal_url, 'name' => $filename, 'date' => $tstamp_str, 'mime' => $mime, 'size' => $fsize)); if (empty($fsize)) { $fsize_str = '-'; } else { // convert to T/G/M/K-bytes: $fsize_str = $this->format_bytes($fsize); } $content = '<dl> <dt>${modified}</dt> <dd class="filemanager-modified">' . $tstamp_str . '</dd> <dt>${type}</dt> <dd class="filemanager-type">' . $mime . '</dd> <dt>${size}</dt> <dd class="filemanager-size">' . $fsize_str . '</dd>'; $content_dl_term = false; $preview_HTML = null; $postdiag_err_HTML = ''; $postdiag_dump_HTML = ''; $thumbnails_done_or_deferred = false; // TRUE: mark our thumbnail work as 'done'; any NULL thumbnails represent deferred generation entries! $check_for_embedded_img = false; $mime_els = explode('/', $mime); for (;;) { switch ($mime_els[0]) { case 'image': /* * thumbnail_gen_mode === 'auto': * * offload the thumbnailing process to another event ('event=thumbnail') to be fired by the client * when it's time to render the thumbnail: * WE simply assume the thumbnail will be there, and when it doesn't, that's * for the event=thumbnail handler to worry about (creating the thumbnail on demand or serving * a generic icon image instead). Meanwhile, we are able to speed up the response process here quite * a bit (rendering thumbnails from very large images can take a lot of time!) * * To further improve matters, we first generate the 250px thumbnail and then generate the 48px * thumbnail from that one (if it doesn't already exist). That saves us one more time processing * the (possibly huge) original image; downscaling the 250px file is quite fast, relatively speaking. * * That bit of code ASSUMES that the thumbnail will be generated from the file argument, while * the url argument is used to determine the thumbnail name/path. */ $emsg = null; try { if (empty($thumb250)) { $thumb250 = $this->getThumb($meta, $file, $this->options['thumbBigSize'], $this->options['thumbBigSize'], $auto_thumb_gen_mode); } if (!empty($thumb250)) { $thumb250_e = FileManagerUtility::rawurlencode_path($thumb250); } if (empty($thumb48)) { $thumb48 = $this->getThumb($meta, !empty($thumb250) ? $this->url_path2file_path($thumb250) : $file, $this->options['thumbSmallSize'], $this->options['thumbSmallSize'], $auto_thumb_gen_mode); } if (!empty($thumb48)) { $thumb48_e = FileManagerUtility::rawurlencode_path($thumb48); } if (empty($thumb48) || empty($thumb250)) { /* * do NOT generate the thumbnail itself yet (it takes too much time!) but do check whether it CAN be generated * at all: THAT is a (relatively speaking) fast operation! */ $imginfo = Image::checkFileForProcessing($file); } $thumbnails_done_or_deferred = true; } catch (Exception $e) { $emsg = $e->getMessage(); $icon48 = $this->getIconForError($emsg, $legal_url, false); $icon = $this->getIconForError($emsg, $legal_url, true); // even cache the fail: that means next time around we don't suffer the failure but immediately serve the error icon instead. } $width = round($this->getID3infoItem($fi, 0, 'video', 'resolution_x')); $height = round($this->getID3infoItem($fi, 0, 'video', 'resolution_y')); $json['width'] = $width; $json['height'] = $height; $content .= ' <dt>${width}</dt><dd>' . $width . 'px</dd> <dt>${height}</dt><dd>' . $height . 'px</dd> </dl>'; $content_dl_term = true; $sw_make = $this->mkSafeUTF8($this->getID3infoItem($fi, null, 'jpg', 'exif', 'IFD0', 'Software')); $time_make = $this->mkSafeUTF8($this->getID3infoItem($fi, null, 'jpg', 'exif', 'IFD0', 'DateTime')); if (!empty($sw_make) || !empty($time_make)) { $content .= '<p>Made with ' . (empty($sw_make) ? '???' : $sw_make) . ' @ ' . (empty($time_make) ? '???' : $time_make) . '</p>'; } // are we delaying the thumbnail generation? When yes, then we need to infer the thumbnail dimensions *anyway*! if (empty($thumb48) && $thumbnails_done_or_deferred) { $dims = $this->predictThumbDimensions($width, $height, $this->options['thumbSmallSize'], $this->options['thumbSmallSize']); $json['thumb48_width'] = $dims['width']; $json['thumb48_height'] = $dims['height']; } if (empty($thumb250)) { if ($thumbnails_done_or_deferred) { // to show the loader.gif in the preview <img> tag, we MUST set a width+height there, so we guestimate the thumbnail250 size as accurately as possible // // derive size from original: $dims = $this->predictThumbDimensions($width, $height, $this->options['thumbBigSize'], $this->options['thumbBigSize']); $preview_HTML = '<a href="' . FileManagerUtility::rawurlencode_path($url) . '" data-milkbox="single" title="' . htmlentities($filename, ENT_QUOTES, 'UTF-8') . '"> <img src="' . $this->options['URLpath4assets'] . 'Images/transparent.gif" class="preview" alt="preview" style="width: ' . $dims['width'] . 'px; height: ' . $dims['height'] . 'px;" /> </a>'; $json['thumb250_width'] = $dims['width']; $json['thumb250_height'] = $dims['height']; } else { // when we get here, a failure occurred before, so we only will have the icons. So we use those: $preview_HTML = '<a href="' . FileManagerUtility::rawurlencode_path($url) . '" data-milkbox="single" title="' . htmlentities($filename, ENT_QUOTES, 'UTF-8') . '"> <img src="' . FileManagerUtility::rawurlencode_path($icon48) . '" class="preview" alt="preview" /> </a>'; } } // else: defer the $preview_HTML production until we're at the end of this and have fetched the actual thumbnail dimensions if (!empty($emsg)) { // use the abilities of modify_json4exception() to munge/format the exception message: $jsa = array('error' => ''); $this->modify_json4exception($jsa, $emsg, 'path = ' . $url); $postdiag_err_HTML .= "\n" . '<p class="err_info">' . $jsa['error'] . '</p>'; if (strpos($emsg, 'img_will_not_fit') !== false) { $earr = explode(':', $emsg, 2); $postdiag_err_HTML .= "\n" . '<p class="tech_info">Estimated minimum memory requirements to create thumbnails for this image: ' . $earr[1] . '</p>'; } } break; case 'text': switch ($mime_els[1]) { case 'directory': $content = '<dl>'; $preview_HTML = ''; break; default: // text preview: $filecontent = @file_get_contents($file, false, null, 0); if ($filecontent === false) { throw new FileManagerException('nofile'); } if (!FileManagerUtility::isBinary($filecontent)) { $preview_HTML = '<pre>' . str_replace(array('$', "\t"), array('$', ' '), htmlentities($filecontent, ENT_NOQUOTES, 'UTF-8')) . '</pre>'; } else { // else: fall back to 'no preview available' (if getID3 didn't deliver instead...) $mime_els[0] = 'unknown'; // remap! continue 3; } break; } break; case 'application': switch ($mime_els[1]) { case 'x-javascript': $mime_els[0] = 'text'; // remap! continue 3; case 'zip': $out = array(array(), array()); $info = $this->getID3infoItem($fi, null, 'zip', 'files'); if (is_array($info)) { foreach ($info as $name => $size) { $name = $this->mkSafeUTF8($name); $isdir = is_array($size); $out[$isdir ? 0 : 1][$name] = '<li><a><img src="' . FileManagerUtility::rawurlencode_path($this->getIcon($name, true)) . '" alt="" /> ' . $name . '</a></li>'; } natcasesort($out[0]); natcasesort($out[1]); $preview_HTML = '<ul>' . implode(array_merge($out[0], $out[1])) . '</ul>'; } break; case 'x-shockwave-flash': $check_for_embedded_img = true; $info = $this->getID3infoItem($fi, null, 'swf', 'header'); if (is_array($info)) { $width = round($this->getID3infoItem($fi, 0, 'swf', 'header', 'frame_width') / 10); $height = round($this->getID3infoItem($fi, 0, 'swf', 'header', 'frame_height') / 10); $json['width'] = $width; $json['height'] = $height; $content .= ' <dt>${width}</dt><dd>' . $width . 'px</dd> <dt>${height}</dt><dd>' . $height . 'px</dd> <dt>${length}</dt><dd>' . round($this->getID3infoItem($fi, 0, 'swf', 'header', 'length') / $this->getID3infoItem($fi, 25, 'swf', 'header', 'frame_count')) . 's</dd> </dl>'; $content_dl_term = true; } break; default: // else: fall back to 'no preview available' (if getID3 didn't deliver instead...) $mime_els[0] = 'unknown'; // remap! continue 3; } break; case 'audio': $check_for_embedded_img = true; $title = $this->mkSafeUTF8($this->getID3infoItem($fi, $this->getID3infoItem($fi, '???', 'tags', 'id3v1', 'title', 0), 'tags', 'id3v2', 'title', 0)); $artist = $this->mkSafeUTF8($this->getID3infoItem($fi, $this->getID3infoItem($fi, '???', 'tags', 'id3v1', 'artist', 0), 'tags', 'id3v2', 'artist', 0)); $album = $this->mkSafeUTF8($this->getID3infoItem($fi, $this->getID3infoItem($fi, '???', 'tags', 'id3v1', 'album', 0), 'tags', 'id3v2', 'album', 0)); $content .= ' <dt>${title}</dt><dd>' . $title . '</dd> <dt>${artist}</dt><dd>' . $artist . '</dd> <dt>${album}</dt><dd>' . $album . '</dd> <dt>${length}</dt><dd>' . $this->mkSafeUTF8($this->getID3infoItem($fi, '???', 'playtime_string')) . '</dd> <dt>${bitrate}</dt><dd>' . round($this->getID3infoItem($fi, 0, 'bitrate') / 1000) . 'kbps</dd> </dl>'; $content_dl_term = true; break; case 'video': $check_for_embedded_img = true; $a_fmt = $this->mkSafeUTF8($this->getID3infoItem($fi, '???', 'audio', 'dataformat')); $a_samplerate = round($this->getID3infoItem($fi, 0, 'audio', 'sample_rate') / 1000, 1); $a_bitrate = round($this->getID3infoItem($fi, 0, 'audio', 'bitrate') / 1000, 1); $a_bitrate_mode = $this->mkSafeUTF8($this->getID3infoItem($fi, '???', 'audio', 'bitrate_mode')); $a_channels = round($this->getID3infoItem($fi, 0, 'audio', 'channels')); $a_codec = $this->mkSafeUTF8($this->getID3infoItem($fi, '', 'audio', 'codec')); $a_streams = $this->getID3infoItem($fi, '???', 'audio', 'streams'); $a_streamcount = is_array($a_streams) ? count($a_streams) : 0; $v_fmt = $this->mkSafeUTF8($this->getID3infoItem($fi, '???', 'video', 'dataformat')); $v_bitrate = round($this->getID3infoItem($fi, 0, 'video', 'bitrate') / 1000, 1); $v_bitrate_mode = $this->mkSafeUTF8($this->getID3infoItem($fi, '???', 'video', 'bitrate_mode')); $v_framerate = round($this->getID3infoItem($fi, 0, 'video', 'frame_rate'), 5); $v_width = round($this->getID3infoItem($fi, '???', 'video', 'resolution_x')); $v_height = round($this->getID3infoItem($fi, '???', 'video', 'resolution_y')); $v_par = round($this->getID3infoItem($fi, 1.0, 'video', 'pixel_aspect_ratio'), 7); $v_codec = $this->mkSafeUTF8($this->getID3infoItem($fi, '', 'video', 'codec')); $g_bitrate = round($this->getID3infoItem($fi, 0, 'bitrate') / 1000, 1); $g_playtime_str = $this->mkSafeUTF8($this->getID3infoItem($fi, '???', 'playtime_string')); $content .= ' <dt>Audio</dt><dd>'; if ($a_fmt === '???' && $a_samplerate == 0 && $a_bitrate == 0 && $a_bitrate_mode === '???' && $a_channels == 0 && empty($a_codec) && $a_streams === '???' && $a_streamcount == 0) { $content .= '-'; } else { $content .= $a_fmt . (!empty($a_codec) ? ' (' . $a_codec . ')' : '') . (!empty($a_channels) ? $a_channels === 1 ? ' (mono)' : ($a_channels === 2 ? ' (stereo)' : ' (' . $a_channels . ' channels)') : '') . ': ' . $a_samplerate . ' kHz @ ' . $a_bitrate . ' kbps (' . strtoupper($a_bitrate_mode) . ')' . ($a_streamcount > 1 ? ' (' . $a_streamcount . ' streams)' : ''); } $content .= '</dd> <dt>Video</dt><dd>' . $v_fmt . (!empty($v_codec) ? ' (' . $v_codec . ')' : '') . ': ' . $v_framerate . ' fps @ ' . $v_bitrate . ' kbps (' . strtoupper($v_bitrate_mode) . ')' . ($v_par != 1.0 ? ', PAR: ' . $v_par : '') . '</dd> <dt>${width}</dt><dd>' . $v_width . 'px</dd> <dt>${height}</dt><dd>' . $v_height . 'px</dd> <dt>${length}</dt><dd>' . $g_playtime_str . '</dd> <dt>${bitrate}</dt><dd>' . $g_bitrate . 'kbps</dd> </dl>'; $content_dl_term = true; break; default: // fall back to 'no preview available' (if getID3 didn't deliver instead...) break; } break; } if (!$content_dl_term) { $content .= '</dl>'; } if (!empty($fi['error'])) { $postdiag_err_HTML .= '<p class="err_info">' . $this->mkSafeUTF8(implode(', ', $fi['error'])) . '</p>'; } $emsgX = null; if (empty($thumb250)) { if (!$thumbnails_done_or_deferred) { // check if we have stored a thumbnail for this file anyhow: $thumb250 = $this->getThumb($meta, $file, $this->options['thumbBigSize'], $this->options['thumbBigSize'], true); if (empty($thumb250)) { if (!empty($fi) && $check_for_embedded_img) { /* * No thumbnail available yet, so find me one! * * When we find a thumbnail during the 'cleanup' scan, we don't know up front if it's suitable to be used directly, * so we treat it as an alternative 'original' file and generate a 250px/48px thumbnail set from it. * * When the embedded thumbnail is small enough, the thumbnail creation process will be simply a copy action, so relatively * low cost. */ $embed = $this->extract_ID3info_embedded_image($fi); //@file_put_contents(dirname(__FILE__) . '/extract_embedded_img.log', print_r(array('html' => $preview_HTML, 'json' => $json, 'thumb250_e' => $thumb250_e, 'thumb250' => $thumb250, 'embed' => $embed, 'fileinfo' => $fi), true)); if (is_object($embed)) { $thumbX = $meta->getThumbURL('embed'); $tfi = pathinfo($thumbX); $tfi['extension'] = image_type_to_extension($embed->metadata[2]); $thumbX = $tfi['dirname'] . '/' . $tfi['filename'] . '.' . $tfi['extension']; $thumbX = $this->normalize($thumbX); $thumbX_f = $this->url_path2file_path($thumbX); // as we've spent some effort to dig out the embedded thumbnail, and 'knowing' (assuming) that generally // embedded thumbnails are not too large, we don't concern ourselves with delaying the thumbnail generation (the // source file mapping is not bidirectional, either!) and go straight ahead and produce the 250px thumbnail at least. $thumb250 = false; $thumb250_e = false; $thumb48 = false; $thumb48_e = false; $meta->mkCacheDir(); if (false === file_put_contents($thumbX_f, $embed->imagedata)) { @unlink($thumbX_f); $emsgX = 'Cannot save embedded image data to cache.'; $icon48 = $this->getIcon('is.default-error', false); $icon = $this->getIcon('is.default-error', true); } else { try { $thumb250 = $this->getThumb($meta, $thumbX_f, $this->options['thumbBigSize'], $this->options['thumbBigSize'], false); if (!empty($thumb250)) { $thumb250_e = FileManagerUtility::rawurlencode_path($thumb250); } $thumb48 = $this->getThumb($meta, !empty($thumb250) ? $this->url_path2file_path($thumb250) : $thumbX_f, $this->options['thumbSmallSize'], $this->options['thumbSmallSize'], false); if (!empty($thumb48)) { $thumb48_e = FileManagerUtility::rawurlencode_path($thumb48); } } catch (Exception $e) { $emsgX = $e->getMessage(); $icon48 = $this->getIconForError($emsgX, $legal_url, false); $icon = $this->getIconForError($emsgX, $legal_url, true); } } } } } else { // !empty($thumb250) $thumb250_e = FileManagerUtility::rawurlencode_path($thumb250); try { $thumb48 = $this->getThumb($meta, $this->url_path2file_path($thumb250), $this->options['thumbSmallSize'], $this->options['thumbSmallSize'], false); assert(!empty($thumb48)); $thumb48_e = FileManagerUtility::rawurlencode_path($thumb48); } catch (Exception $e) { $emsgX = $e->getMessage(); $icon48 = $this->getIconForError($emsgX, $legal_url, false); $icon = $this->getIconForError($emsgX, $legal_url, true); $thumb48 = false; $thumb48_e = false; } } } } else { if (empty($thumb250_e)) { $thumb250_e = FileManagerUtility::rawurlencode_path($thumb250); } if (empty($thumb48)) { try { $thumb48 = $this->getThumb($meta, $this->url_path2file_path($thumb250), $this->options['thumbSmallSize'], $this->options['thumbSmallSize'], false); assert(!empty($thumb48)); $thumb48_e = FileManagerUtility::rawurlencode_path($thumb48); } catch (Exception $e) { $emsgX = $e->getMessage(); $icon48 = $this->getIconForError($emsgX, $legal_url, false); $icon = $this->getIconForError($emsgX, $legal_url, true); $thumb48 = false; $thumb48_e = false; } } if (empty($thumb48_e)) { $thumb48_e = FileManagerUtility::rawurlencode_path($thumb48); } } // also provide X/Y size info with each direct-access thumbnail file: if (!empty($thumb250)) { $json['thumb250'] = $thumb250_e; $meta->store('thumb250_direct', $thumb250); $tnsize = $meta->fetch('thumb250_info'); if (empty($tnsize)) { $tnsize = getimagesize($this->url_path2file_path($thumb250)); $meta->store('thumb250_info', $tnsize); } if (is_array($tnsize)) { $json['thumb250_width'] = $tnsize[0]; $json['thumb250_height'] = $tnsize[1]; if (empty($preview_HTML)) { $preview_HTML = '<a href="' . FileManagerUtility::rawurlencode_path($url) . '" data-milkbox="single" title="' . htmlentities($filename, ENT_QUOTES, 'UTF-8') . '"> <img src="' . $thumb250_e . '" class="preview" alt="' . (!empty($emsgX) ? $this->mkSafe4HTMLattr($emsgX) : 'preview') . '" style="width: ' . $tnsize[0] . 'px; height: ' . $tnsize[1] . 'px;" /> </a>'; } } } if (!empty($thumb48)) { $json['thumb48'] = $thumb48_e; $meta->store('thumb48_direct', $thumb48); $tnsize = $meta->fetch('thumb48_info'); if (empty($tnsize)) { $tnsize = getimagesize($this->url_path2file_path($thumb48)); $meta->store('thumb48_info', $tnsize); } if (is_array($tnsize)) { $json['thumb48_width'] = $tnsize[0]; $json['thumb48_height'] = $tnsize[1]; } } if ($thumbnails_done_or_deferred && (empty($thumbs250) || empty($thumbs48))) { $json['thumbs_deferred'] = true; } else { $json['thumbs_deferred'] = false; } if (!empty($icon48)) { $icon48_e = FileManagerUtility::rawurlencode_path($icon48); $json['icon48'] = $icon48_e; } if (!empty($icon)) { $icon_e = FileManagerUtility::rawurlencode_path($icon); $json['icon'] = $icon_e; } $fi4dump = null; if (!empty($fi)) { try { $fi4dump = $meta->fetch('file_info_dump'); if (empty($fi4dump)) { $fi4dump = array_merge(array(), $fi); // clone $fi $this->clean_ID3info_results($fi4dump); $meta->store('file_info_dump', $fi4dump); } $dump = FileManagerUtility::table_var_dump($fi4dump, false); $postdiag_dump_HTML .= "\n" . $dump . "\n"; //@file_put_contents(dirname(__FILE__) . '/getid3.log', print_r(array('html' => $preview_HTML, 'json' => $json, 'thumb250_e' => $thumb250_e, 'thumb250' => $thumb250, 'embed' => $embed, 'fileinfo' => $fi), true)); } catch (Exception $e) { $postdiag_err_HTML .= '<p class="err_info">' . $e->getMessage() . '</p>'; } } if ($preview_HTML === null) { $preview_HTML = '${nopreview}'; } if (!empty($preview_HTML)) { //$content .= '<h3>${preview}</h3>'; $content .= '<div class="filemanager-preview-content">' . $preview_HTML . '</div>'; } if (!empty($postdiag_err_HTML)) { $content .= '<div class="filemanager-errors">' . $postdiag_err_HTML . '</div>'; } if (!empty($postdiag_dump_HTML) && $metaHTML_mode) { $content .= '<div class="filemanager-diag-dump">' . $postdiag_dump_HTML . '</div>'; } $json['content'] = self::compressHTML($content); $json['metadata'] = $metaJSON_mode ? $fi4dump : null; return array_merge(is_array($json_in) ? $json_in : array(), $json); }
/** * Produce a HTML snippet detailing the given file. * * Return NULL on error. */ public function extractDetailInfo($legal_url, $file, $mime) { $url = $this->legal2abs_url_path($legal_url); $filename = pathinfo($url, PATHINFO_BASENAME); $content = null; if (FileManagerUtility::startsWith($mime, 'image/')) { // generates a random number to put on the end of the image, to prevent caching //$randomImage = '?'.md5(uniqid(rand(),1)); // getID3 is slower as it *copies* the image to the temp dir before processing: see GetDataImageSize(). // This is done as getID3 can also analyze *embedded* images, for which this approach is required. $getid3 = new getID3(); $getid3->encoding = 'UTF-8'; $getid3->Analyze($file); //$size = @getimagesize($file); //// check for badly formatted image files (corruption); we'll handle the overly large ones next //if (!$size) // throw new FileManagerException('corrupt_img:' . $url); $sw_make = $this->getID3infoItem($getid3, null, 'jpg', 'exif', 'IFD0', 'Software'); $time_make = $this->getID3infoItem($getid3, null, 'jpg', 'exif', 'IFD0', 'DateTime'); $content = '<dl> <dt>${width}</dt><dd>' . $this->getID3infoItem($getid3, 0, 'video', 'resolution_x') . 'px</dd> <dt>${height}</dt><dd>' . $this->getID3infoItem($getid3, 0, 'video', 'resolution_y') . 'px</dd> </dl>'; if (!empty($sw_make) || !empty($time_make)) { $content .= '<p>Made with ' . (empty($sw_make) ? '???' : $sw_make) . ' @ ' . (empty($time_make) ? '???' : $time_make) . '</p>'; } $content .= ' <h2>${preview}</h2> '; $emsg = null; try { $thumbfile = $this->getThumb($legal_url, $file); } catch (Exception $e) { $emsg = $e->getMessage(); $thumbfile = $this->getIconForError($emsg, $legal_url, false); } $content .= '<a href="' . FileManagerUtility::rawurlencode_path($url) . '" data-milkbox="preview" title="' . htmlentities($filename, ENT_QUOTES, 'UTF-8') . '"> <img src="' . FileManagerUtility::rawurlencode_path($thumbfile) . '" class="preview" alt="preview" /> </a>'; if (!empty($emsg) && strpos($emsg, 'img_will_not_fit') !== false) { $earr = explode(':', $e->getMessage(), 2); $content .= "\n" . '<p class="tech_info">Estimated minimum memory requirements to create thumbnails for this image: ' . $earr[1] . '</p>'; } $finfo = Image::guestimateRequiredMemorySpace($file); if (!empty($finfo['usage_guestimate']) && !empty($finfo['usage_min_advised'])) { $content .= "\n" . '<p class="tech_info">memory used: ' . number_format(memory_get_peak_usage() / 1000000.0, 1) . ' MB / estimated: ' . number_format($finfo['usage_guestimate'] / 1000000.0, 1) . ' MB / suggested: ' . number_format($finfo['usage_min_advised'] / 1000000.0, 1) . ' MB</p>'; } $exif_data = $this->getID3infoItem($getid3, null, 'jpg', 'exif'); try { if (!empty($exif_data)) { /* * before dumping the EXIF data array (which may carry binary content and MAY CRASH the json_encode()r >:-(( * we filter it to prevent such crashes and oddly looking (diagnostic) presentation of values. */ self::clean_EXIF_results($exif_data); ob_start(); var_dump($exif_data); //return $content; $dump = ob_get_clean(); $content .= $dump; } } catch (Exception $e) { $content .= 'kleppertje: ' . $e->getMessage(); } } elseif (FileManagerUtility::startsWith($mime, 'text/') || $mime == 'application/x-javascript') { // text preview: $filecontent = @file_get_contents($file, false, null, 0); if ($filecontent === false) { throw new FileManagerException('nofile'); } if (!FileManagerUtility::isBinary($filecontent)) { $content = '<div class="textpreview"><pre>' . str_replace(array('$', "\t"), array('$', ' '), htmlentities($filecontent, ENT_NOQUOTES, 'UTF-8')) . '</pre></div>'; } // else: fall back to 'no preview available' } elseif ($mime == 'application/zip') { $out = array(array(), array()); $getid3 = new getID3(); $getid3->Analyze($file); $info = $this->getID3infoItem($getid3, null, 'zip', 'files'); if (is_array($info)) { foreach ($info as $name => $size) { $isdir = is_array($size) ? true : false; $out[$isdir ? 0 : 1][$name] = '<li><a><img src="' . FileManagerUtility::rawurlencode_path($this->getIcon($name, true)) . '" alt="" /> ' . $name . '</a></li>'; } natcasesort($out[0]); natcasesort($out[1]); $content = '<ul>' . implode(array_merge($out[0], $out[1])) . '</ul>'; } } elseif ($mime == 'application/x-shockwave-flash') { $getid3 = new getID3(); $getid3->Analyze($file); $info = $this->getID3infoItem($getid3, null, 'swf', 'header'); if (is_array($info)) { // Note: preview data= urls were formatted like this in CCMS: // $this->options['assetBasePath'] . 'dewplayer.swf?mp3=' . rawurlencode($url) . '&volume=30' $content = '<dl> <dt>${width}</dt><dd>' . $this->getID3infoItem($getid3, 0, 'swf', 'header', 'frame_width') / 10 . 'px</dd> <dt>${height}</dt><dd>' . $this->getID3infoItem($getid3, 0, 'swf', 'header', 'frame_height') / 10 . 'px</dd> <dt>${length}</dt><dd>' . round($this->getID3infoItem($getid3, 0, 'swf', 'header', 'length') / $this->getID3infoItem($getid3, 25, 'swf', 'header', 'frame_count')) . 's</dd> </dl> <h2>${preview}</h2> <div class="object"> <object type="application/x-shockwave-flash" data="' . FileManagerUtility::rawurlencode_path($url) . '" width="500" height="400"> <param name="scale" value="noscale" /> <param name="movie" value="' . FileManagerUtility::rawurlencode_path($url) . '" /> </object> </div>'; } } elseif (FileManagerUtility::startsWith($mime, 'audio/')) { $getid3 = new getID3(); $getid3->Analyze($file); getid3_lib::CopyTagsToComments($getid3->info); $dewplayer = FileManagerUtility::rawurlencode_path($this->options['assetBasePath'] . 'dewplayer.swf'); // Note: these next several indexed array fetches were marked with @ in CCMS to catch some failures... // // TODO: do it cleaner then that! // // DONE! $content = '<dl> <dt>${title}</dt><dd>' . $this->getID3infoItem($getid3, '???', 'comments', 'title', 0) . '</dd> <dt>${artist}</dt><dd>' . $this->getID3infoItem($getid3, '???', 'comments', 'artist', 0) . '</dd> <dt>${album}</dt><dd>' . $this->getID3infoItem($getid3, '???', 'comments', 'album', 0) . '</dd> <dt>${length}</dt><dd>' . $this->getID3infoItem($getid3, '???', 'playtime_string') . '</dd> <dt>${bitrate}</dt><dd>' . round($this->getID3infoItem($getid3, 0, 'bitrate') / 1000) . 'kbps</dd> </dl> <h2>${preview}</h2> <div class="object"> <object type="application/x-shockwave-flash" data="' . $dewplayer . '" width="200" height="20" id="dewplayer" name="dewplayer"> <param name="wmode" value="transparent" /> <param name="movie" value="' . $dewplayer . '" /> <param name="flashvars" value="mp3=' . FileManagerUtility::rawurlencode_path($url) . '&volume=50&showtime=1" /> </object> </div>'; } else { // else: fall back to 'no preview available' try { $getid3 = new getID3(); $getid3->encoding = 'UTF-8'; $getid3->Analyze($file); ob_start(); var_dump($getid3->info); $dump = ob_get_clean(); // $dump may dump object IDs and other binary stuff, which will completely b0rk json_encode: make it palatable: // strip the NULs out: $dump = str_replace('�', '?', $dump); //$dump = html_entity_decode(strip_tags($dump), ENT_QUOTES, 'UTF-8'); //@file_put_contents('getid3.raw.log', $dump); // since the regex matcher leaves NUL bytes alone, we do those above in undecoded form; the rest is treated here $dump = preg_replace("/[^ -~\n\r\t]/", '?', $dump); // remove everything outside ASCII range; some of the high byte values seem to crash json_encode()! // and reduce long sequences of unknown charcodes: $dump = preg_replace('/\\?{8,}/', '???????', $dump); //$dump = html_entity_encode(strip_tags($dump), ENT_NOQUOTES, 'UTF-8'); $content = '<div class="margin"> <h2>${preview}</h2> <pre>' . "\n" . $dump . "\n" . '</pre></div>'; //@file_put_contents('getid3.log', $dump); return $content; } catch (Exception $e) { // ignore $content = $e->getMessage(); } $content = '<div class="margin"> ${nopreview} ' . $content . ' </div>'; } return self::compressHTML($content); }