Files
Yuba/Yuba.php
2018-08-08 23:12:47 -07:00

1128 lines
30 KiB
PHP
Executable File

<?php
// Yuba
// //
//////////////////////////////////////////
$version = "0.6.9";
ini_set('memory_limit', '4096M');
date_default_timezone_set("America/Los_Angeles");
$time_start = microtime(true);
// Includes & Prefs
//////////////////////////////////////////
require("functions.php");
require("filetypes.php");
$wopt_noprofile = 1;
$p = unserialize(file_get_contents("prefs.php"));
// Path & application variables
//////////////////////////////////////////
if (!isset($argv[1])) { echo "Input error"; die; }
$zpath = realpath(@$argv[1]);
if (@$argv[2]) { $bdest = realpath($argv[2]); } else { $bdest = realpath($p['bdest']); }
if (!is_dir($zpath) | !is_dir($bdest)) { echo "Filepath error"; die; }
// Check for bundle
if ($zpath == "/") { $blabel = "root"; } else { $blabel = preg_replace("/[^A-Za-z0-9\.]/", "_", basename($zpath)); }
if (is_writable($zpath)) { $p['paranoid'] = 1; } else { $p['paranoid'] = 0; }
$bpath = chop($bdest,"/")."/".substr(crc32($zpath),0,3)."_".$blabel.".bundle";
if (!is_dir($bpath)) { mkdir($bpath); }
if (!is_dir($bpath."/thumbs")) { mkdir($bpath."/thumbs"); }
// Treat these directories as files
$p['bundles'] = array( "app",
"bundle",
"sparsebundle",
"photoslibrary",
"aplibrary",
"apvault",
"abbu",
"calendar",
"framework",
"plugin",
"kext",
"rtfd"
);
foreach ($p['bundles'] as $bundle) {
$p['nodescend'][] = "*.".$bundle;
}
// Ignore matching files and directories
$p['ignore'] = array( ".DS_Store",
".DocumentRevisions-V100",
".Spotlight-V100",
".TemporaryItems",
".apdisk",
".com.apple.timemachine.donotpresent",
".fseventsd",
".metadata-never-index",
".neofinder.abemeda.volinfo.xml"
);
// Metadata tools
$bin_gfi = __DIR__."/bin/GetFileInfo";
$bin_mediainfo = __DIR__."/bin/mediainfo";
$bin_exiftool = __DIR__."/bin/exiftool";
$bin_ffmpeg = __DIR__."/bin/ffmpeg";
$bin_qlthumb = __DIR__."/bin/ql-thumbnail";
// Banner
//////////////////////////////////////////
$banner = "Yuba: ".$zpath." -> ".$bpath;
echo $banner."\n".str_repeat("-", strlen($banner))."\n";
// Disk info
//////////////////////////////////////////
echo "Gathering system info...\n";
$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";
}
if ($wopt_noprofile) {
$profile = "disabled";
} else {
$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
//////////////////////////////////////////
echo "Building database...\n";
$stamp = date("Y-m-d_H-i-s", time());
$dbo = new PDO("sqlite:".$bpath."/".$stamp.".sqlite3");
$dbo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/*
$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->exec("CREATE TABLE _walkwalk (
version TEXT,
opts TEXT,
host TEXT,
uid INTEGER,
zpath TEXT,
bpath TEXT,
type TEXT,
passed_file INTEGER,
passed_dir INTEGER,
passed_link INTEGER,
passed_total INTEGER,
nodescended INTEGER,
ignored INTEGER,
dupes INTEGER,
stats TEXT,
qlmanage TEXT,
sysvers TEXT,
diskutil TEXT,
disks TEXT,
profile TEXT,
status TEXT
)");
$dbo->exec("CREATE TABLE family (
pid TEXT,
fid TEXT,
children TEXT
)");
/*
Gather for each file:
A. IDs
pid (path ID)
fid (file ID)
B. splFileInfo methods
Pathname
Path
Filename
Extension
Type
Inode
Perms
Owner
ATime
CTime
MTime
LinkTarget
RealPath
C. External methods
stat
items
newest
gfi_type
gfi_attr
gfi_created
D. Aggregates
Size (splFileInfo, du)
Title (exiftool, kMDItemTitle, mediainfo)
PixelWidth (kMDItemPixelWidth, exiftool, mediainfo)
PixelHeight (kMDItemPixelHeight, exiftool, mediainfo)
Duration (kMDItemDurationSeconds, mediainfo, exiftool)
DateTimeOriginal (exiftool[DateTimeOriginal],mediainfo[EncodedDate],exiftool[CreateDate,MediaCreateDate],kMDItemContentCreationDate)
Origin (exiftool[CameraModelName,Producer,CreatorTool,WriterName,Software,Encoder],mediainfo[WritingApplication])
GPS (exiftool[GPSPosition], kMDItemLatitude.kMDItemLongitude)
Author (exiftool[Author,Artist,Creator,By-line])
E. Spotlight
spotlight (whole plist)
kMDItemDateAdded
kMDItemLastUsedDate
kMDItemUseCount
kMDItemContentModificationDate
kMDItemContentType
kMDItemCreator
kMDItemFSCreatorCode
kMDItemKind
kMDItemFSTypeCode
kMDItemUserTags
kMDItemFSInvisible
kMDItemNumberOfPages
kMDItemPageHeight
kMDItemPageWidth
kMDItemWhereFroms
kMDItemEncodingApplications
F. Pool
has_exif
has_mediainfo
has_hash
thumb_filename
thumb_width
thumb_height
G. Exiftool
ProfileDescription
BitDepth
Compression
WhiteBalance
Orientation
LensType
H. Mediainfo
VideoFormat
AudioFormat
Tracks
Profile
Bitrate
*/
$dbo->exec("CREATE TABLE files (
pid TEXT,
fid TEXT,
Pathname TEXT,
Path TEXT,
Filename TEXT,
Extension TEXT,
Type TEXT,
Inode INTEGER,
Perms INTEGER,
Owner TEXT,
ATime INTEGER,
CTime INTEGER,
MTime INTEGER,
LinkTarget TEXT,
RealPath TEXT,
stat TEXT,
items INTEGER,
newest INTEGER,
gfi_type TEXT,
gfi_attr TEXT,
gfi_created TEXT,
Size INTEGER,
Title TEXT,
PixelWidth INTEGER,
PixelHeight INTEGER,
Duration INTEGER,
DateTimeOriginal INTEGER,
Origin TEXT,
GPS TEXT,
Author TEXT,
spotlight TEXT,
kMDItemDateAdded INTEGER,
kMDItemLastUsedDate INTEGER,
kMDItemUseCount INTEGER,
kMDItemContentModificationDate INTEGER,
kMDItemContentType TEXT,
kMDItemCreator TEXT,
kMDItemFSCreatorCode TEXT,
kMDItemKind TEXT,
kMDItemFSTypeCode TEXT,
kMDItemUserTags TEXT,
kMDItemFSInvisible INTEGER,
kMDItemNumberOfPages INTEGER,
kMDItemPageHeight INTEGER,
kMDItemPageWidth INTEGER,
kMDItemWhereFroms TEXT,
kMDItemEncodingApplications TEXT,
has_exif INTEGER,
has_mediainfo INTEGER,
has_hash INTEGER,
thumb_filename TEXT,
thumb_width INTEGER,
thumb_height INTEGER,
ProfileDescription TEXT,
BitDepth INTEGER,
Compression TEXT,
Orientation INTEGER,
LensType TEXT,
VideoFormat TEXT,
AudioFormat TEXT,
Tracks INTEGER,
Profile TEXT,
Bitrate INTEGER
)");
$stmt = $dbo->prepare("INSERT INTO _walkwalk VALUES (:version, :opts, :host, :uid, :zpath, :bpath, :type, :passed_file, :passed_dir, :passed_link, :passed_total, :nodescended, :ignored, :dupes, :stats, :qlmanage, :sysvers, :diskutil, :disks, :profile, :status)");
$stmt->BindValue(":version",$version);
$stmt->BindValue(":opts",serialize($p));
$stmt->BindValue(":host",$host);
$stmt->BindValue(":uid",posix_getuid());
$stmt->BindValue(":zpath",$zpath);
$stmt->BindValue(":bpath",$bpath);
$stmt->BindValue(":type",$type);
$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();
// Iterator
//////////////////////////////////////////
$first_run = 1;
$passed_file = $passed_dir = $passed_link = $passed_total = $nodescended = $ignored = 0;
$files = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator(
$zpath,
RecursiveDirectoryIterator::SKIP_DOTS
),
function ($current, $key, $iterator) use ($p) {
global $nodescended, $ignored, $passed_file, $passed_dir, $passed_link, $passed_total, $first_run;
$clean = true;
// identify ignore files
if (is_array($p['ignore'])) {
foreach ($p['ignore'] as $wildcard) {
if (fnmatch($wildcard, $current->getFilename())) {
$clean = false;
if ($first_run) { $ignored++; }
}
}
}
// identify nodescend dirs
if (is_array($p['nodescend'])) {
foreach ($p['nodescend'] as $wildcard) {
if (fnmatch($wildcard, $current->getPath())) {
$clean = false;
if ($first_run) { $nodescended++; }
}
}
}
//tally stats
if ($clean && $first_run) {
if ($current->getType() == "file") {
$passed_file++;
} elseif ($current->getType() == "dir") {
$passed_dir++;
} elseif ($current->getType() == "link") {
$passed_link++;
}
$passed_total++;
}
return $clean;
}
),
RecursiveIteratorIterator::SELF_FIRST,
RecursiveIteratorIterator::CATCH_GET_CHILD
);
// Tally
//////////////////////////////////////////
foreach ($files as $null) { }
$first_run = 0;
// Permissions
//////////////////////////////////////////
if (posix_getuid()) {
echo ProgressBar::start($passed_total,"File permissions");
echo "You are not root. Checking file readability";
$oops = 0;
foreach ($files as $splFileInfo) {
$path = $splFileInfo->getRealPath();
if ($path && !is_readable($path)) {
$oops = 1;
echo "x";
} else {
echo ".";
}
echo ProgressBar::next();
//echo "\t".$path."\n";
}
echo ProgressBar::finish();
echo "\n";
if ($oops) {
echo "Some files could not be read. Stopping.";
die;
}
} else {
echo "Running as root. Some QuickLook plugins may not be available.";
echo "\n";
}
if ($p['paranoid']) {
echo "Filesystem is writable. ";
if ($p['fixatimes']) {
echo "Preserving atimes.";
} else {
echo "Preserving ctimes.";
}
echo "\n";
}
// Pool DB
//////////////////////////////////////////
$dbp = new PDO("sqlite:".$bpath."/pool.sqlite3");
$dbp->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbp->exec("CREATE TABLE IF NOT EXISTS md5 (fid TEXT, hash TEXT)");
$dbp->exec("CREATE TABLE IF NOT EXISTS exiftool (fid TEXT, tags TEXT)");
$dbp->exec("CREATE TABLE IF NOT EXISTS mediainfo (fid TEXT, info TEXT)");
$dbp->exec("CREATE TABLE IF NOT EXISTS thumbs (fid TEXT, created INTEGER, relative_path TEXT, width INTEGER, height INTEGER, tool TEXT)");
// Prescan
//////////////////////////////////////////
$family = array();
$fids = array();
echo ProgressBar::start($passed_total,"Prescan");
foreach ($files as $splFileInfo) {
$pathname = $splFileInfo->getPathname();
$path = $splFileInfo->getPath();
$key = md5($pathname);
$pkey = md5($path);
if (array_key_exists($key, $family)) {
echo "Duplicate key on ".$pathname."\n"; die;
}
$family[$key] = array();
// Path-agnostic Unique File ID (to prevent redundant hashes and thumbs)
if ($splFileInfo->getType() != "dir" && $splFileInfo->getType() != "link") {
$fid = md5($splFileInfo->getSize().$splFileInfo->getMtime().$splFileInfo->getBasename());
$dx[$fid][] = $pathname;
$fx[] = array($fid, $pathname);
$family[$key]['fid'] = $fid;
}
// Parents
//$family[$key]['parents'] = getParents($zpath, $pathname);
// Children
$family[$pkey]['children'][] = $key;
echo ProgressBar::next();
}
echo ProgressBar::finish();
// Debug record of duplicate FIDs
$dupes = array_filter($dx, function($a) { return count($a) > 1; });
$dxo = var_export($dupes, true);
if (strlen($dxo)) {
file_put_contents($bpath."/".$stamp."_dupes.txt",$dxo);
$dupecount = count($dupes,COUNT_RECURSIVE) - count($dupes);
echo floor(($dupecount/$passed_total)*100)." percent of files look like duplicates\n";
}
// Write family to DB
$message = "Writing family to DB: ";
$message .= $passed_file." files, ";
$message .= $passed_dir." dirs, ";
$message .= $nodescended." bundles, ";
$message .= $passed_link." links, ";
$message .= $ignored." ignored, ";
$message .= ($dupecount ? $dupecount : 0)." dupes";
echo ProgressBar::start(count($family),$message);
foreach ($family as $key => $item) {
$stmt = $dbo->prepare("INSERT INTO family VALUES (:pid, :fid, :children)");
$stmt->BindValue(":pid",$key);
if (@$item['fid']) {
$stmt->BindValue(":fid",$item['fid']);
}
if (@$item['children'] && is_array(@$item['children'])) {
$stmt->BindValue(":children",serialize($item['children']));
}
$stmt->execute();
echo ProgressBar::next();
}
echo ProgressBar::finish();
unset($dx, $dxo, $dupes);
// stats
$stmt = "UPDATE _walkwalk SET ";
$stmt .= "passed_file=".$passed_file.", ";
$stmt .= "passed_dir=".$passed_dir.", ";
$stmt .= "passed_link=".$passed_link.", ";
$stmt .= "passed_total=".$passed_total.", ";
$stmt .= "nodescended=".$nodescended.", ";
$stmt .= "ignored=".$ignored.", ";
$stmt .= "dupes=".($dupecount ? $dupecount : 0);
$dbo->exec($stmt);
// Thumbnails
//////////////////////////////////////////
if ($p['thumbs']) {
echo ProgressBar::start(count($fx),"Generating thumbnails");
foreach ($fx as $array) {
$fid = $array[0];
$pathname = $array[1];
$ext = pathinfo($pathname,PATHINFO_EXTENSION);
$tpath = $bpath."/thumbs/".substr($fid, 0, 2);
if (!is_dir($tpath)) { mkdir($tpath); }
$tfile = $tpath."/".$fid.".jpg";
// HACK for ql-thumbnail bug
$t_skip = array("emlx");
if (count($t_skip) && in_array($ext, $t_skip)) {
echo ProgressBar::next("Skipping ".shortlabel($pathname));
continue;
}
// if no thumb file, then poll database
if (file_exists($tfile)) {
echo ProgressBar::next("Thumb file found for ".shortlabel($pathname));
continue;
} elseif ($dbp->query("SELECT EXISTS(SELECT 1 FROM thumbs WHERE fid='".$fid."')")->fetch()[0]) {
echo ProgressBar::next("Thumb record found for ".shortlabel($pathname));
continue;
} else {
echo ProgressBar::next("Generating thumb for ".shortlabel($pathname));
}
$stmt = $dbp->prepare("INSERT INTO thumbs VALUES (:fid, :created, :relative_path, :width, :height, :tool)");
$stmt->BindValue(":fid",$fid);
$stmt->BindValue(":created",time());
$shellpath = escapeshellarg($pathname);
// first try to make a thumb with external tools
$cmd = null;
if (in_array($ext, $t_files['sips'])) {
//$cmd = $bin_tv." ".$shellpath." -o ".$tfile."[Q=90,optimize_coding] --size=".$p['thumb_size'];
$cmd = "sips -s format jpeg -s formatOptions 80 --resampleHeightWidthMax ".$p['thumb_size']." ".$shellpath." --out ".$tfile;
$stmt->BindValue(":tool","sips");
} elseif (in_array($ext, $t_files['ffmpeg'])) {
//$cmd = $bin_tf." -i ".$shellpath." -o ".$tfile." -s ".$p['thumb_size']." -c jpg -q 8.5";
$cmd = $bin_ffmpeg." -ss $(( $(".$bin_mediainfo." --Inform='Video;%Duration%' ".$shellpath.") / 10000 )) -i ".$shellpath." -vframes 1 -filter:v scale='400:-1' -q:v 3 ".$tfile;
$stmt->BindValue(":tool","ffmpeg");
}
if ($cmd) { shell_exec($cmd." 2>&1"); }
// if those tools failed, try quicklook
if (!@filesize($tfile)) {
//$cmd = $bin_qlthumb." ".$shellpath." ".$tfile." public.jpeg-2000 ".$p['thumb_size']." ".$p['thumb_size']." .8";
$cmd = $bin_qlthumb." ".$shellpath." ".$tfile." public.jpeg ".$p['thumb_size']." ".$p['thumb_size']." .8";
shell_exec($cmd." 2>&1");
$stmt->BindValue(":tool","quicklook");
}
// success, move thumb into the bundle
if (file_exists($tfile) && @filesize($tfile)) {
$stmt->BindValue(":relative_path",substr($tfile, strlen($bpath)));
list($width, $height) = getimagesize($tfile);
$stmt->BindValue(":width",$width);
$stmt->BindValue(":height",$height);
}
$stmt->execute();
}
echo ProgressBar::finish();
}
// External metadata
//////////////////////////////////////////
if ($p['meta']) {
echo ProgressBar::start(count($fx),"Collecting external metadata");
foreach ($fx as $array) {
$fid = $array[0];
$pathname = $array[1];
$shellpath = escapeshellarg($pathname);
$ext = pathinfo($pathname,PATHINFO_EXTENSION);
if (!in_array($ext, $e_files) && !in_array($ext, $m_files)) {
echo ProgressBar::next("Not a media file: ".shortlabel($pathname));
continue;
} else {
echo ProgressBar::next("Metadata: ".shortlabel($pathname));
}
if (in_array($ext, $e_files)) {
$check = $dbp->query("SELECT EXISTS(SELECT 1 FROM exiftool WHERE fid='".$fid."')")->fetch()[0];
if (!$check) {
$rawexif = eval("return ".`$bin_exiftool -php $shellpath`);
$stmt = $dbp->prepare("INSERT INTO exiftool VALUES (:fid, :tags)");
$stmt->BindValue(":fid",$fid);
$stmt->BindValue(":tags",serialize($rawexif[0]));
$stmt->execute();
}
}
if (in_array($ext, $m_files)) {
$check = $dbp->query("SELECT EXISTS(SELECT 1 FROM mediainfo WHERE fid='".$fid."')")->fetch()[0];
if (!$check) {
$stmt = $dbp->prepare("INSERT INTO mediainfo VALUES (:fid, :info)");
$stmt->BindValue(":fid",$fid);
$stmt->BindValue(":info",serialize(parseMediaInfo(shell_exec($bin_mediainfo." --Output=OLDXML ".$shellpath." 2>&1"))));
$stmt->execute();
}
}
}
echo ProgressBar::finish();
}
// Hashes
//////////////////////////////////////////
if ($p['hash']) {
if ($p['hash_limit']) {
$message = "Generating hashes for files under ".$p['hash_limit']."GB";
} else {
$message = "Generating hashes for all files";
}
echo ProgressBar::start(count($fx),$message);
foreach ($fx as $array) {
$fid = $array[0];
$pathname = $array[1];
$size = filesize($pathname);
$limit = $p['hash_limit']*1000000000;
$check = $dbp->query("SELECT EXISTS(SELECT 1 FROM md5 WHERE fid='".$fid."')")->fetch()[0];
if ($check) {
echo ProgressBar::next("Hash already exists: ".shortlabel($pathname));
} elseif ($p['hash_limit'] && ($size > $limit)) {
echo ProgressBar::next("Too big to hash: ".shortlabel($pathname)." (".human_filesize($size).")");
} else {
echo ProgressBar::next("Generating hash: ".shortlabel($pathname));
$stmt = $dbp->prepare("INSERT INTO md5 VALUES (:fid, :hash)");
$stmt->BindValue(":fid",$fid);
$stmt->BindValue(":hash",md5_file($pathname));
$stmt->execute();
}
}
echo ProgressBar::finish();
}
// Files
//////////////////////////////////////////
echo ProgressBar::start($passed_total,"Processing files");
foreach ($files as $splFileInfo) {
echo "\n";
// DB
$stmt = $dbo->prepare("INSERT INTO files VALUES (:pid, :fid, :Pathname, :Path, :Filename, :Extension, :Type, :Inode, :Perms, :Owner, :ATime, :CTime, :MTime, :LinkTarget, :RealPath, :stat, :items, :newest, :gfi_type, :gfi_attr, :gfi_created, :Size, :Title, :PixelWidth, :PixelHeight, :Duration, :DateTimeOriginal, :Origin, :GPS, :Author, :spotlight, :kMDItemDateAdded, :kMDItemLastUsedDate, :kMDItemUseCount, :kMDItemContentModificationDate, :kMDItemContentType, :kMDItemCreator, :kMDItemFSCreatorCode, :kMDItemKind, :kMDItemFSTypeCode, :kMDItemUserTags, :kMDItemFSInvisible, :kMDItemNumberOfPages, :kMDItemPageHeight, :kMDItemPageWidth, :kMDItemWhereFroms, :kMDItemEncodingApplications, :has_exif, :has_mediainfo, :has_hash, :thumb_filename, :thumb_width, :thumb_height, :ProfileDescription, :BitDepth, :Compression, :Orientation, :LensType, :VideoFormat, :AudioFormat, :Tracks, :Profile, :Bitrate)");
// Identify dir, file, link or bundle dir
$type = $splFileInfo->getType();
if ($type == "dir") {
foreach ($p['bundles'] as $bundle) {
$check = ".".$bundle;
if (substr($splFileInfo->getFilename(), -(strlen($check)), strlen($check)) == $check) { $type = "bundle"; }
}
}
$stmt->BindValue(":Type",$type);
// Cache atime before it gets modified
if ($type != "link") { $atime = $splFileInfo->getATime(); }
// Path basics
$pathname = $splFileInfo->getPathname();
$path = $splFileInfo->getPath();
$filename = $splFileInfo->getFilename();
$extension = $splFileInfo->getExtension();
$shellpath = escapeshellarg($pathname);
$stmt->BindValue(":Pathname",$pathname);
$stmt->BindValue(":Path",$path);
$stmt->BindValue(":Filename",$filename);
$stmt->BindValue(":Extension",$extension);
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());
}
echo shortlabel($pathname,50,1);
// ------------------------------------------------ //
// Get stat
if ($type != "link") {
$stat = chop(@shell_exec("stat -x ".$shellpath." 2>&1"));
} else {
$stat = null;
}
$stmt->BindValue(":stat",@$stat);
// Cache stat
if ($type != "link" && $p['paranoid']) {
$pre_access = null;
$pre_modify = null;
$pre_change = null;
foreach (explode("\n", $stat) as $line) {
$check = substr($line, 0, 6);
if ($check == "Access") { $pre_access = $line; }
if ($check == "Modify") { $pre_modify = $line; }
if ($check == "Change") { $pre_change = $line; }
}
}
// Generate PID and FID
$pid = md5($pathname);
$stmt->BindValue(":pid",$pid);
if ($type == "file") {
$fid = md5($splFileInfo->getSize().$splFileInfo->getMtime().$splFileInfo->getBasename());
$stmt->BindValue(":fid",$fid);
} else {
$stmt->BindValue(":fid",null);
}
// Size
if ($type == "dir" || $type == "bundle") {
$size = trim(shell_exec("du -ks ".$shellpath." | cut -f1"))*1024;
} elseif ($type == "file") {
$size = $splFileInfo->getSize();
} else {
$size = null;
}
$stmt->BindValue(":Size",@$size);
stringPrint(floor($size/1024)."k");
// ------------------------------------------------ //
// Items
if ($type == "dir" || $type == "bundle" ) {
$items = chop(@shell_exec("find ".$shellpath." \( ! -regex '.*/\..*' \) | wc -l 2>&1"))-1;
$stmt->BindValue(":items",@$items);
stringPrint($items ? "ITEMS" : "items");
} else {
$items = null;
stringPrint(" ");
}
// ------------------------------------------------ //
// Newest
if ($type == "dir") {
$newest = @filemtime(chop(shell_exec("find ".$shellpath." -type f -not -path '*/\.*' -print0 | xargs -0 stat -f \"%m %N\" | sort -rn 2>&1 | head -1 | cut -f2- -d\" \"")));
$stmt->BindValue(":newest",@$newest);
stringPrint($newest ? "NEWEST" : "newest");
} else {
$newest = null;
stringPrint(" ");
}
// ------------------------------------------------ //
// GetFileInfo
$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");
// ------------------------------------------------ //
// Spotlight
$mdls = null;
$mdls = shell_exec("mdls -plist - ".$shellpath." 2>&1");
if ($mdls != $pathname.": could not find ".$pathname.".\n") {
$parser = new plistParser();
$spotlight = $parser->parseString($mdls);
//$stmt->BindValue(":spotlight",serialize($spotlight));
$stmt->BindValue(":spotlight",$mdls);
} else {
$spotlight = array();
$stmt->BindValue(":spotlight",null);
}
stringPrint($mdls ? "MDLS" : "mdls");
unset($breakout, $schema, $item, $ready);
$breakout[] = array ("kMDItemDateAdded", "date");
$breakout[] = array ("kMDItemLastUsedDate", "date");
$breakout[] = array ("kMDItemUseCount", 0);
$breakout[] = array ("kMDItemContentModificationDate", "date");
$breakout[] = array ("kMDItemContentType", 0);
$breakout[] = array ("kMDItemCreator", 0);
$breakout[] = array ("kMDItemFSCreatorCode", 0);
$breakout[] = array ("kMDItemKind", 0);
$breakout[] = array ("kMDItemFSTypeCode", 0);
$breakout[] = array ("kMDItemUserTags", "array");
$breakout[] = array ("kMDItemFSInvisible", 0);
$breakout[] = array ("kMDItemNumberOfPages", 0);
$breakout[] = array ("kMDItemPageHeight", 0);
$breakout[] = array ("kMDItemPageWidth", 0);
$breakout[] = array ("kMDItemWhereFroms", "array");
$breakout[] = array ("kMDItemEncodingApplications", "array");
foreach ($breakout as $schema) {
if (!isset($spotlight[$schema[0]])) {
$stmt->BindValue(":".$schema[0],null);
continue;
}
if ($schema[1] === "date") {
$ready = strtotime($spotlight[$schema[0]]);
} elseif ($schema[1] === "array") {
$ready = serialize($spotlight[$schema[0]]);
} else {
$ready = $spotlight[$schema[0]];
}
$stmt->BindValue(":".$schema[0],$ready);
}
unset($breakout);
// ------------------------------------------------ //
// Pool
if ($type == "file") {
unset($fetch_exif, $fetch_media, $fetch_hash, $fetch_thumb, $yes_exif, $yes_media, $yes_hash);
$fetch_exif = @unserialize($dbp->query("SELECT tags FROM exiftool WHERE fid='".$fid."'")->fetch()[0]);
is_array($fetch_exif) ? $yes_exif = 1 : $yes_exif = 0;
$stmt->BindValue(":has_exif",$yes_exif);
stringPrint($yes_exif ? "EXIF" : "exif");
$fetch_media = @unserialize($dbp->query("SELECT info FROM mediainfo WHERE fid='".$fid."'")->fetch()[0]);
is_array($fetch_media) ? $yes_media = 1 : $yes_media = 0;
$stmt->BindValue(":has_mediainfo",$yes_media);
stringPrint($yes_media ? "MEDIA" : "media");
$yes_hash = $dbp->query("SELECT EXISTS(SELECT 1 FROM md5 WHERE fid='".$fid."')")->fetch()[0];
$stmt->BindValue(":has_hash",$yes_hash);
stringPrint($yes_hash ? "HASH" : "hash");
$fetch_thumb = $dbp->query("SELECT * FROM thumbs WHERE fid='".$fid."'")->fetch();
if (@$fetch_thumb['relative_path']) {
$stmt->BindValue(":thumb_filename",$fetch_thumb['relative_path']);
$stmt->BindValue(":thumb_width",$fetch_thumb['width']);
$stmt->BindValue(":thumb_height",$fetch_thumb['height']);
stringPrint("THUMB");
} else {
$stmt->BindValue(":thumb_filename",null);
stringPrint("thumb");
}
$breakout[] = "ProfileDescription";
$breakout[] = "BitDepth_BitsPerSample";
$breakout[] = "Compression";
$breakout[] = "Aperture,LightSource,WhiteBalance";
$breakout[] = "Orientation";
$breakout[] = "LensType,FocalLength";
$breakout['profile'] = "ProfileDescription";
$breakout['bits'] = "BitDepth_BitsPerSample";
$breakout['compression'] = "Compression";
$breakout[] = "Aperture,LightSource,WhiteBalance";
$breakout[] = "Orientation";
$breakout[] = "LensType,FocalLength";
/*
function parseConditionalItem($data, $item) {
if (strpos($item, "_")) {
$list = explode("_", $item);
foreach ($list as $piece) {
// left off here
}
}
function parseItem($data, $item) {
if (strpos($item, ",")) {
$list = explode(",", $item);
foreach ($list as $piece) {
$cleared[] = parseConditionalItem($piece);
}
} else {
$cleared[] = parseConditionalItem($item);
}
foreach ($cleared as $check) {
if (isset($data[$check])) {
$ready[] = $data[$check];
}
}
if (@count($ready) > 1) {
return implode(", ",$ready);
} elseif (@count($ready) == 1) {
return $ready[0];
} else {
return null;
}
}
// left off here
foreach ($breakout as $item) {
unset($ready);
if (strpos($item, ",")) {
$list = explode(",", $item) {
foreach ($list as $multi) {
if (isset($fetch_exif[$multi])) {
$ready[] = $fetch_exif[$multi];
}
}
} elseif (strpos($item, "_")) {
$list = explode("_", $item) {
foreach ($list as $multi) {
if (isset($ready) {
continue;
}
if (isset($fetch_exif[$multi])) {
$ready[] = $fetch_exif[$multi];
}
*/
unset($breakout);
//print_r($fetch_exif);
//print_r($fetch_media);
}
// Write to DB
$stmt->execute();
stringPrint("DB");
// Set fileatime back to original value
if ($type != "link" && is_writable($pathname) && $p['fixatimes']) {
@exec("touch -at `date -r ".$atime." +%Y%m%d%H%M.%S` ".$shellpath." 2>&1");
stringPrint("touch");
}
// Double check stat for file against pre-run value
if ($type != "link" && $p['paranoid']) {
$restat = chop(@shell_exec("stat -x ".$shellpath." 2>&1"));
$post_access = null;
$post_modify = null;
$post_change = null;
foreach (explode("\n", $restat) as $line) {
$check = substr($line, 0, 6);
if ($check == "Access") { $post_access = $line; }
if ($check == "Modify") { $post_modify = $line; }
if ($check == "Change") { $post_change = $line; }
}
$message = array();
if ($pre_access != $post_access) {
$message[] = "ATIME";
}
if ($pre_modify != $post_modify) {
$message[] = "MTIME";
}
if ($pre_change != $post_change) {
$message[] = "CTIME";
}
if (count($message)) { stringPrint("Changed: ".implode(", ", $message)); }
}
echo "\n";
echo ProgressBar::next();
}
echo ProgressBar::finish();
// Cleanup
//////////////////////////////////////////
echo "\n";
$seconds = floor($time = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]);
$dbo->exec("UPDATE _walkwalk SET status='completed_in_".$seconds."'");
echo "Finished in ".$seconds." seconds\n\n";
unset($dbo, $dbp, $files, $family, $fx);
?>