Files
Yuba/Yuba.php
2017-06-16 00:14:32 -07:00

821 lines
24 KiB
PHP
Executable File

#!/usr/bin/php
<?php
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
date_default_timezone_set("America/Los_Angeles");
$time_start = microtime(true);
// Yuba
// //
//////////////////////////////////////////
$version = "0.4.6";
// Stat each file before and after reading (will fail on ctime unless volume is RO)
if (in_array("-paranoid", $argv)) { $wopt_paranoid = 1; } else { $wopt_paranoid = 0; }
// Treat these directories as files
$wopt_bundles = array( "app",
"bundle",
"sparsebundle",
"photoslibrary",
"aplibrary",
"apvault",
"abbu",
"calendar",
"framework",
"plugin",
"kext",
"rtfd"
);
foreach ($wopt_bundles as $bundle) {
$wopt_nodescend[] = "*.".$bundle;
}
// Ignore matching files and directories
$wopt_ignore = array( ".DS_Store",
".DocumentRevisions-V100",
".Spotlight-V100",
".TemporaryItems",
".apdisk",
".com.apple.timemachine.donotpresent",
".fseventsd",
".metadata-never-index",
".neofinder.abemeda.volinfo.xml"
);
if (in_array("-hash", $argv)) { $wopt_hash = 1; } else { $wopt_hash = 0; }
//$wopt_hash_limit = ""; // don't hash large files nyi
//$wopt_mediainfo = 1; // not yet implemented
//$wopt_exiftool = 1; // not yet implemented
//$wopt_thumb = 1; // not yet implemented
$wopt_thumb_size = "256";
$wopt_thumb_factor = $wopt_thumb_size/128;
// Location of binaries used to collect metadata
$bin_gfi = "/Applications/Xcode.app/Contents/Developer/usr/bin/GetFileInfo";
$bin_mediainfo = "/opt/local/bin/mediainfo";
$bin_exiftool = "/opt/local/bin/exiftool";
// Functions
function debugStat() {
global $shellpath;
echo "\n\n";
echo $shellpath." - ".chop(@shell_exec("stat -x ".$shellpath." | tail -n1"));
echo "\n\n";
}
function stringPrint($string) {
echo $string.@str_repeat(" ", (10-strlen($string)));
}
function getWoptString() {
global $wopt_nodescend, $wopt_ignore, $wopt_hash, $wopt_mediainfo, $wopt_exiftool, $wopt_thumb_size, $wopt_thumb_factor, $wopt_tmpdir, $wopt_paranoid;
return array( array("nodescend", $wopt_nodescend),
array("ignore", $wopt_ignore),
array("hash", $wopt_hash),
array("mediainfo", $wopt_mediainfo),
array("exiftool", $wopt_exiftool),
array("thumb_size", $wopt_thumb_size),
array("thumb_factor", $wopt_thumb_factor),
array("wopt_paranoid", $wopt_paranoid)
);
}
class plistParser extends XMLReader {
public function parseString($string) { $this->XML($string); return $this->process(); }
private function process() {
$this->read();
if($this->nodeType !== XMLReader::DOC_TYPE || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 2); }
if(!$this->next("plist") || $this->nodeType !== XMLReader::ELEMENT || $this->name !== "plist") { throw new Exception(sprintf("Error parsing plist. nodeType: %d -- Name: %s", $this->nodeType, $this->name), 3); }
$plist = array(); while($this->read()) { if($this->nodeType == XMLReader::ELEMENT) { $plist[] = $this->parse_node(); } }
if(count($plist) == 1 && $plist[0]) { return $plist[0]; } else { return $plist; }
}
private function parse_node() {
if($this->nodeType !== XMLReader::ELEMENT) return;
switch($this->name) {
case 'data': return base64_decode($this->getNodeText()); break;
case 'real': return floatval($this->getNodeText()); break;
case 'string': return $this->getNodeText(); break;
case 'integer': return intval($this->getNodeText()); break;
case 'date': return $this->getNodeText(); break;
case 'true': return true; break;
case 'false': return false; break;
case 'array': return $this->parse_array(); break;
case 'dict': return $this->parse_dict(); break;
default: throw new Exception(sprintf("Not a valid plist. %s is not a valid type", $this->name), 4);
}
}
private function parse_dict() {
$array = array(); $this->nextOfType(XMLReader::ELEMENT);
do { if($this->nodeType !== XMLReader::ELEMENT || $this->name !== "key") { if(!$this->next("key")) { return $array; } } $key = $this->getNodeText(); $this->nextOfType(XMLReader::ELEMENT); $array[$key] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "dict")); return $array;
}
private function parse_array() {
$array = array(); $this->nextOfType(XMLReader::ELEMENT);
do { $array[] = $this->parse_node(); $this->nextOfType(XMLReader::ELEMENT, XMLReader::END_ELEMENT); }
while($this->nodeType && !$this->isNodeOfTypeName(XMLReader::END_ELEMENT, "array")); return $array;
}
private function getNodeText() { $string = $this->readString(); $this->nextOfType(XMLReader::END_ELEMENT); return $string; }
private function nextOfType() { $types = func_get_args(); $this->read(); while($this->nodeType && !(in_array($this->nodeType, $types))) { $this->read(); } }
private function isNodeOfTypeName($type, $name) { return $this->nodeType === $type && $this->name === $name; }
}
function parseMediaInfo ($xml) {
$xml = simplexml_load_string($xml);
$data = array();
$data['version'] = (string) $xml['version'];
foreach ($xml->File->track as $track) {
$trackType = strtolower($track['type']);
$trackId = isset($track['streamid']) ? $track['streamid'] : 1;
$trackId = (string)$trackId;
$trackData = [];
foreach ($track as $rawKey => $rawVal) {
$key = strtolower($rawKey);
$val = (string)$rawVal;
if ($key == 'stream_identifier') { continue; }
if (!array_key_exists($key, $trackData)) {
$trackData[$key] = array($val);
} elseif (!in_array($val, $trackData[$key])) {
$trackData[$key][] = $val;
}
}
if ($trackType == 'general') {
$data['file']['general'] = $trackData;
} else {
$data['file'][$trackType][$trackId] = $trackData;
}
}
return $data;
}
function bashcolor($str,$fgcolor="white",$bgcolor=null) {
static $fgcolors = array('black' => '0;30', 'dark gray' => '1;30', 'blue' => '0;34', 'light blue' => '1;34', 'green' => '0;32', 'light green' => '1;32', 'cyan' => '0;36', 'light cyan' => '1;36', 'red' => '0;31', 'light red' => '1;31', 'purple' => '0;35', 'light purple' => '1;35', 'brown' => '0;33', 'yellow' => '1;33', 'light gray' => '0;37', 'white' => '1;37', 'underline' => '4');
static $bgcolors = array('black' => '40', 'red' => '41', 'green' => '42', 'yellow' => '43', 'blue' => '44', 'magenta' => '45', 'cyan' => '46', 'light gray' => '47');
$out="";
if (!isset($fgcolors[$fgcolor])) { $fgcolor='white'; }
if (!isset($bgcolors[$bgcolor])) { $bgcolor=null; }
if ($fgcolor) { $out .= "\033[{$fgcolors[$fgcolor]}m"; }
if ($bgcolor) { $out .= "\033[{$bgcolors[$bgcolor]}m"; }
$out .= $str."\033[0m";
return $out;
}
// Path arguments
$zpath = realpath($argv[1]);
if (!is_dir($zpath)) { echo "Usage: walk <path> <dbfile>"; die; }
if (isset($argv[2]) && is_dir($argv[2])) {
$dbprefix = realpath($argv[2]);
} else {
$dbprefix = ".";
}
// File checks
$stamp = date("Y-m-d_H-i-s", time());
$wopt_tmpdir = "/tmp/WalkWalk_".$stamp."/";
if (!is_dir($wopt_tmpdir)) { mkdir($wopt_tmpdir); }
$base = preg_replace("/[^A-Za-z0-9\.]/", "_", basename($zpath));
if (!$base) { $base = "root"; }
$dbfile = $dbprefix."/".$stamp."_".$base.".sqlite3";
if (file_exists($dbfile)) { echo "File \"".$dbfile."\" already exists!"; die; }
// Banner
echo "Yuba ".$version."\n";
echo "-----------------------------------------------\n";
$banner = $zpath." -> ".$dbfile;
echo $banner."\n";
echo str_repeat("-", strlen($banner))."\n";
// Disk info
$host = gethostname();
$disks = shell_exec("diskutil list 2>&1");
if (substr($zpath, 0, 9) != "/Volumes/") {
$zbase = "/";
} else {
$zparts = explode("/", $zpath);
$zbase = "/Volumes/".$zparts[2];
}
$diskutil = shell_exec("diskutil info ".$zbase." 2>&1");
$getstats = array( "Volume Name",
"Protocol",
"Volume UUID",
"Device Location",
"Volume Total Space",
"Volume Available Space",
"Level Type"
);
foreach ($getstats as $stat) {
preg_match("/(".$stat.":)(.*)(\n)/",$diskutil,$matches);
if (isset($matches[2])) {
if (substr($stat, -5, 5) == "Space") {
$pieces = explode(" ", trim($matches[2]));
$summary = $pieces[0]." ".$pieces[1];
$stats[$stat] = $summary;
} else {
$stats[$stat] = trim($matches[2]);
}
}
}
$dstats = serialize($stats);
if ($zpath == "/") {
$type = "Startup disk";
} elseif (strtolower($zpath) == strtolower("/Volumes/".$stats["Volume Name"])) {
if ($stats["Protocol"] == "Disk Image") {
$type = "Disk image";
} else {
$type = "External disk";
}
} else {
$type = "Folder";
}
$profile = shell_exec("system_profiler SPHardwareDataType SPStorageDataType SPThunderboltDataType SPUSBDataType 2>&1");
$qlmanage = shell_exec("qlmanage -m 2>&1");
$sysvers = shell_exec("sw_vers 2>&1");
// Database
// use mysql?
//$dbo = new PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $pass);
$dbo = new PDO("sqlite:".$dbfile);
$dbo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// test: try to set values for better performance
//$dbo->query("PRAGMA page_size = 4096");
//$dbo->query("PRAGMA cache_size = 10000");
//$dbo->query("PRAGMA locking_mode = EXCLUSIVE");
//$dbo->query("PRAGMA synchronous = NORMAL");
//$dbo->query("PRAGMA journal_mode = WAL");
//$dbo->query("PRAGMA cache_size = 5000");
// end test
$dbo->exec("CREATE TABLE files (
id INTEGER PRIMARY KEY,
parent INTEGER,
Pathname TEXT,
Path TEXT,
Filename TEXT,
Extension TEXT,
Type TEXT,
items INTEGER,
stat TEXT,
LinkTarget TEXT,
RealPath TEXT,
Inode INTEGER,
Size INTEGER,
Perms INTEGER,
Owner TEXT,
ATime INTEGER,
MTime INTEGER,
CTime INTEGER,
gfi_type TEXT,
gfi_attr TEXT,
gfi_created TEXT,
hash TEXT,
tinfo TEXT
)");
$dbo->exec("CREATE TABLE mdls (
id INTEGER PRIMARY KEY,
hasmeta INTEGER,
DateAdded TEXT,
ContentType TEXT,
Creator TEXT,
Kind TEXT,
UserTags TEXT,
FSInvisible INTEGER,
PixelWidth INTEGER,
PixelHeight INTEGER,
spotlight TEXT
)");
$dbo->exec("CREATE TABLE metadata (
id INTEGER PRIMARY KEY,
duration TEXT,
mediainfo TEXT,
exiftool TEXT
)");
$dbo->exec("CREATE TABLE thumbs (
id INTEGER PRIMARY KEY,
thumb BLOB
)");
$dbo->exec("CREATE TABLE _walkwalk (
version TEXT,
opts TEXT,
host TEXT,
zpath TEXT,
type TEXT,
nodescended INTEGER,
ignored INTEGER,
stats TEXT,
qlmanage TEXT,
sysvers TEXT,
diskutil TEXT,
disks TEXT,
profile TEXT,
status TEXT
)");
$stmt = $dbo->prepare("INSERT INTO _walkwalk VALUES (:version, :opts, :host, :zpath, :type, :nodescended, :ignored, :stats, :qlmanage, :sysvers, :diskutil, :disks, :profile, :status)");
$stmt->BindValue(":version",$version." (".posix_getuid().")");
$stmt->BindValue(":opts",serialize(getWoptString()));
$stmt->BindValue(":host",$host);
$stmt->BindValue(":zpath",$zpath);
$stmt->BindValue(":type",$type);
$stmt->BindValue(":nodescended",null);
$stmt->BindValue(":ignored",null);
$stmt->BindValue(":stats",$dstats);
$stmt->BindValue(":qlmanage",$qlmanage);
$stmt->BindValue(":sysvers",$sysvers);
$stmt->BindValue(":diskutil",$diskutil);
$stmt->BindValue(":disks",$disks);
$stmt->BindValue(":profile",$profile);
$stmt->BindValue(":status","aborted");
$stmt->execute();
// Iterate
$nodescended = 0;
$ignored = 0;
$files = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator(
// start in parent dir to include self
dirname($zpath),
RecursiveDirectoryIterator::SKIP_DOTS
),
function ($current, $key, $iterator) use ($wopt_ignore, $wopt_nodescend) {
global $nodescended, $ignored, $zpath;
$clean = true;
// ensure we don't traverse zpath siblings
if ($zpath != "/" && (substr($current->getRealpath(), 0, strlen($zpath)+1) != $zpath."/") && ($current->getRealpath() != $zpath)) {
$clean = false;
}
// filenames to ignore
if (is_array($wopt_ignore)) {
foreach ($wopt_ignore as $wildcard) {
if (fnmatch($wildcard, $current->getFilename())) {
$clean = false;
$ignored++;
echo "\nSkipping: ".$current->getRealpath()."\n\n";
}
}
}
// directories to ignore
if (is_array($wopt_nodescend)) {
foreach ($wopt_nodescend as $wildcard) {
if (fnmatch($wildcard, $current->getPath())) {
$clean = false;
$nodescended++;
echo "\nNodescending: ".$current->getRealpath()."\n\n";
}
}
}
return $clean;
}
),
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
// Debug input array
/*
foreach ($files as $splFileInfo) {
echo "====================================================================================\n";
print_r($splFileInfo);
echo "====================================================================================\n";
echo "getRealPath = ".$splFileInfo->getRealPath()."\n";
echo "getPathname = ".$splFileInfo->getPathname()."\n";
echo "isLink = ".$splFileInfo->isLink()."\n";
if ($splFileInfo->isLink()) {
echo "getLinkTarget = ".$splFileInfo->getLinkTarget()."\n";
} else {
echo "getLinkTarget = N/A\n";
}
echo "getType = ".$splFileInfo->getType()." (".filetype($splFileInfo->getPathname()).")\n";
echo "isDir = ".$splFileInfo->isDir()."\n";
echo "isFile = ".$splFileInfo->isFile()."\n";
echo "-----------------------------------------------------------------------\n";
echo "getPath = ".$splFileInfo->getPath()."\n";
echo "getFilename = ".$splFileInfo->getFilename()."\n";
echo "getBasename = ".$splFileInfo->getBasename()." (".basename($splFileInfo->getPathname()).")\n";
echo "getExtension = ".$splFileInfo->getExtension()."\n";
echo "-----------------------------------------------------------------------\n";
if (!$splFileInfo->isLink()) {
echo "getATime = ".$splFileInfo->getAtime()." (".fileatime($splFileInfo->getPathname()).")\n";
echo "getMTime = ".$splFileInfo->getMtime()." (".filemtime($splFileInfo->getPathname()).")\n";
echo "getCTime = ".$splFileInfo->getCtime()." (".filectime($splFileInfo->getPathname()).")\n";
echo "getInode = ".$splFileInfo->getInode()." (".fileinode($splFileInfo->getPathname()).")\n";
echo "getPerms = ".$splFileInfo->getPerms()." (".fileperms($splFileInfo->getPathname()).")\n";
echo "getGroup = ".$splFileInfo->getGroup()." (".filegroup($splFileInfo->getPathname()).")\n";
echo "getOwner = ".$splFileInfo->getOwner()." (".fileowner($splFileInfo->getPathname()).")\n";
echo "getSize = ".$splFileInfo->getSize()." (".filesize($splFileInfo->getPathname()).")\n";
}
}
die;
*/
// Check perms
if (posix_getuid()) {
echo bashcolor("You are not root. Checking file readability: ", "red");
$oops = 0;
foreach ($files as $splFileInfo) {
$path = $splFileInfo->getRealPath();
if (!is_readable($path)) {
$oops = 1;
echo "x";
} else {
echo ".";
}
}
echo "\n\n";
if ($oops) {
echo "Some files could not be read. Continue? (Y/n)";
$line = trim(fgets(fopen("php://stdin","r")));
$line = $line ?: "y";
if($line != "y"){
echo "Exiting!\n"; die;
}
}
} else {
echo bashcolor("Running as root. Some QuickLook plugins may not be available.", "red");
}
// Filetypes for special handling
$m_files = array( "mkv",
"ogg",
"avi",
"wav",
"mpeg",
"mpg",
"vob",
"mp4",
"m2v",
"mp3",
"asf",
"wma",
"wmv",
"qt",
"mov",
"rm",
"ifo",
"ac3",
"dts",
"aac",
"ape",
"flac",
"aiff",
"m2ts" );
$e_files = array( "ai",
"aiff",
"ape",
"asf",
"avi",
"bmp",
"divx",
"dng",
"doc",
"docx",
"eps",
"epub",
"exe",
"exif",
"fla",
"flac",
"flv",
"gif",
"icc",
"iso",
"jpg",
"jpeg",
"m2ts",
"m4a",
"m4b",
"m4v",
"mkv",
"mobi",
"azw",
"azw3",
"mov",
"qt",
"mp3",
"mp4",
"mpeg",
"mpg",
"m2v",
"nef",
"numbers",
"ogg",
"pages",
"pdf",
"pict",
"png",
"ppm",
"ppt",
"psd",
"psb",
"qif",
"raw",
"rtf",
"sr2",
"srf",
"svg",
"swf",
"tiff",
"tif",
"torrent",
"vcf",
"vob",
"wav",
"webm",
"wma",
"wmv",
"xls",
"xlsx",
"xmp",
"zip" );
foreach ($e_files as $ext) { $e_files[] = strtoupper($ext); }
foreach ($m_files as $ext) { $m_files[] = strtoupper($ext); }
// Inserts
foreach ($files as $splFileInfo) {
$type = $splFileInfo->getType();
if ($type == "dir") {
foreach ($wopt_bundles as $bundle) {
$check = ".".$bundle;
if (substr($splFileInfo->getFilename(), -(strlen($check)), strlen($check)) == $check) { $type = "bundle"; }
}
}
if ($type != "link") { $atime = $splFileInfo->getATime(); }
$pathname = $splFileInfo->getPathname();
$path = $splFileInfo->getPath();
$filename = $splFileInfo->getFilename();
$extension = $splFileInfo->getExtension();
$shellpath = escapeshellarg($pathname);
debugStat();
if (!$type) { echo "\nBREAK: can't determine type of ".$pathname; die; }
if ($type != "link") {
$stat = chop(@shell_exec("stat -x ".$shellpath." 2>&1"));
if ($wopt_paranoid && !$atime) { echo "\nBREAK: Cannot determine atime of ".$pathname; die; }
} else {
$stat = null;
}
if ($type == "dir" || $type == "bundle" ) {
$items = chop(@shell_exec("find ".$shellpath." \( ! -regex '.*/\..*' \) | wc -l 2>&1"))-1;
} else {
$items = null;
}
$echolabel = basename($pathname);
echo $echolabel.": ";
$pad = 80;
if (strlen($echolabel) < $pad) {
echo str_repeat(" ",($pad-strlen($echolabel)));
}
// Determine ID of parent dir by querying database
$parent = $dbo->query("SELECT id FROM files WHERE (Pathname='".str_replace("'", "''", $path)."')")->fetch()['id'];
stringPrint("parent");
debugStat();
// Gather file attributes
$stmt = $dbo->prepare("INSERT INTO files VALUES (:id, :parent, :Pathname, :Path, :Filename, :Extension, :Type, :items, :stat, :LinkTarget, :RealPath, :Inode, :Size, :Perms, :Owner, :ATime, :MTime, :CTime, :gfi_type, :gfi_attr, :gfi_created, :hash, :tinfo)");
if ($type == "dir") {
$size = shell_exec("du -ks ".$shellpath)*1024;
} elseif ($type == "file" || $type == "bundle") {
$size = $splFileInfo->getSize();
} else {
$size = null;
}
$stmt->BindValue(":Size",@$size);
stringPrint(floor($size/1024)."k");
if ($parent) {
$stmt->BindValue(":parent",$parent);
} else {
$stmt->BindValue(":parent",0);
}
$stmt->BindValue(":items",@$items);
$stmt->BindValue(":stat",@$stat);
$stmt->BindValue(":Pathname",$pathname);
$stmt->BindValue(":Path",$path);
$stmt->BindValue(":Filename",$filename);
$stmt->BindValue(":Extension",$extension);
$stmt->BindValue(":Type",$type);
if ($type == "link") {
$stmt->BindValue(":LinkTarget",$splFileInfo->getLinkTarget());
$stmt->BindValue(":RealPath",$splFileInfo->getRealPath());
} else {
$stmt->BindValue(":Inode",$splFileInfo->getInode());
$stmt->BindValue(":Perms",$splFileInfo->getPerms());
$stmt->BindValue(":Owner",$splFileInfo->getOwner().":".$splFileInfo->getGroup());
$stmt->BindValue(":ATime",$atime);
$stmt->BindValue(":CTime",$splFileInfo->getCTime());
$stmt->BindValue(":MTime",$splFileInfo->getMTime());
}
debugStat();
stringPrint("attr");
$gfiparts = explode("\n", chop(shell_exec($bin_gfi." -P ".$shellpath." 2>&1")));
if (is_array($gfiparts)) {
foreach ($gfiparts as $line) {
list($label, $value) = explode(": ", $line);
$gfi[$label] = isset($value) ? trim($value,"\"") : null;
}
}
$writegfitype = @$gfi['type'].":".@$gfi['creator'];
if ($writegfitype == "\\0\\0\\0\\0:\\0\\0\\0\\0" || $writegfitype == ":") { $writegfitype = null; }
$stmt->BindValue("gfi_type",$writegfitype);
$stmt->BindValue("gfi_attr",@$gfi['attributes']);
$stmt->BindValue("gfi_created",strtotime($gfi['created']));
stringPrint("gfi");
if ($wopt_hash && $type != "link") {
$stmt->BindValue(":hash",md5_file($pathname));
StringPrint("hash");
} else {
$stmt->BindValue(":hash",null);
StringPrint("(x)hash");
}
$thumb = $wopt_tmpdir.$filename.".png";
/*
// insane workaround for insane apple bug
if (@pathinfo($pathname)['extension'] == "mp3" | "MP3" | "m4a" | "M4A" | "m4b" | "M4B" ) {
$zprefix = "sudo qlmanage";
} else {
$zprefix = "qlmanage";
}
*/
$zprefix = "qlmanage";
@exec($zprefix." -t -f ".$wopt_thumb_factor." -o ".$wopt_tmpdir." ".$shellpath." 2>&1");
stringPrint("thumb");
if ($size && !file_exists($thumb) && (in_array($extension, $m_files) || in_array($extension, $e_files))) {
@exec("ffmpegthumbnailer -i ".$shellpath." -o \"".$thumb."\" -s ".$wopt_thumb_size." -c png 2>&1");
stringPrint("fthumb");
} else {
stringPrint("(x)fthumb");
}
if (file_exists($thumb) && filesize($thumb)) {
$stmt->BindValue(":tinfo",serialize(getimagesize($thumb)));
}
debugStat();
$stmt->execute();
stringPrint("->files");
// Gather spotlight metadata
$stmt = $dbo->prepare("INSERT INTO mdls VALUES (:id, :hasmeta, :DateAdded, :ContentType, :Creator, :Kind, :UserTags, :FSInvisible, :PixelWidth, :PixelHeight, :spotlight)");
$mdls = shell_exec("mdls -plist - ".$shellpath." 2>&1");
stringPrint("mdls");
if ($mdls != $pathname.": could not find ".$pathname.".\n") {
$stmt->BindValue(":hasmeta",1);
$parser = new plistParser();
$spotlight = $parser->parseString($mdls);
$stmt->BindValue(":DateAdded",@strtotime($spotlight['kMDItemDateAdded']));
$stmt->BindValue(":ContentType",@$spotlight['kMDItemContentType']);
$stmt->BindValue(":Creator",@$spotlight['kMDItemCreator']);
$stmt->BindValue(":Kind",@$spotlight['kMDItemKind']);
if (isset($spotlight['kMDItemUserTags'])) {
$stmt->BindValue(":UserTags",serialize($spotlight['kMDItemUserTags']));
}
$stmt->BindValue(":FSInvisible",@$spotlight['kMDItemFSInvisible']);
$stmt->BindValue(":PixelWidth",@$spotlight['kMDItemPixelWidth']);
$stmt->BindValue(":PixelHeight",@$spotlight['kMDItemPixelHeight']);
$stmt->BindValue(":spotlight",serialize($spotlight));
} else {
$stmt->BindValue(":hasmeta",0);
}
$stmt->execute();
stringPrint("->mdls");
// Gather external metadata
$stmt = $dbo->prepare("INSERT INTO metadata VALUES (:id, :duration, :mediainfo, :exiftool)");
if ($type != "dir" && in_array($extension, $m_files)) {
$minfo = parseMediaInfo(shell_exec($bin_mediainfo." --Output=XML ".$shellpath." 2>&1"));
if ($minfo['file']['general']['duration'][0]) {
$stmt->BindValue(":duration",$minfo['file']['general']['duration'][0]);
} else {
$stmt->BindValue(":duration",null);
}
$stmt->BindValue(":mediainfo",serialize($minfo));
stringPrint("minfo");
} else {
$stmt->BindValue(":duration",null);
$stmt->BindValue(":mediainfo",null);
stringPrint("(x)info");
}
if ($type != "dir" && $type != "link" && in_array($extension, $e_files)) {
$stmt->BindValue(":exiftool",serialize(eval("return ".`$bin_exiftool -php $shellpath`)));
stringPrint("etool");
} else {
$stmt->BindValue(":exiftool",null);
stringPrint("(x)etool");
}
$stmt->execute();
stringPrint("->meta");
// Gather thumbnail
debugStat();
$stmt = $dbo->prepare("INSERT INTO thumbs VALUES (:id, :thumb)");
if (file_exists($thumb) && filesize($thumb)) {
$stmt->BindValue(":thumb",file_get_contents($thumb));
} else {
$stmt->BindValue(":thumb",null);
}
$stmt->execute();
stringPrint("->thumb");
// Set fileatime back to original value
//if ($type != "link" && is_writable($pathname)) {
// @exec("touch -at `date -r ".$atime." +%Y%m%d%H%M.%S` ".$shellpath." 2>&1");
// stringPrint("touch");
// }
echo "\n";
// Double check stat for file against pre-run value
echo bashcolor(str_replace(array("\n"," "),array(" ",""),$stat)."\n","blue");
if ($wopt_paranoid && $type != "link") {
$restat = chop(@shell_exec("stat -x ".$shellpath." 2>&1"));
echo bashcolor(str_replace(array("\n"," "),array(" ",""),$restat)."\n","green");
if ($stat != $restat) { echo "\nBREAK: stat changed on ".$pathname; die; }
}
}
// Footer
$seconds = floor($time = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]);
$fbanner = "Finished in ".$seconds." seconds";
echo str_repeat("-", strlen($fbanner))."\n".$fbanner."\n";
echo "Files ignored: ".$ignored." / Files nodescended: ".$nodescended."\n";
// Write app summary values
$dbo->exec("UPDATE _walkwalk SET nodescended=".$nodescended.", ignored=".$ignored.", status='completed_in_".$seconds."'");
?>