Read A Folder And Split Sub-Folder Names Into MySQL Inserts - php

I have a folder named "Comics" and sub folders in that directory with the names of comics + the issue
Example:
/Comics <-- Main Folder
/Amazing Spider-Man 129 <-- Sub Folder
/Hellblazer 100 <-- Sub Folder
/Zatanna 01 <-- Sub Folder
Now what i want to do is scan the Comics directory and output each folder name as a mysql insert query. The actual folder name needs to be seperated as "Comic Name" & "Comic Issue".
Example Query
mysql_query("INSERT INTO comics (name, issue) VALUES ('Amazing Spider-Man', '129')");
I got this far and now i want to add a query check to see if the comic exists or not.
<?php
$main_folder = 'K:/Comics/'; // should be K:\Comics\ but I changed it because of the highlighting issue
$folders = glob($main_folder.'* [0-9]*', GLOB_ONLYDIR);
$comics_series = array();
foreach($folders as $folder){
$comics_series[] = preg_split('/(.+)\s(\d+)/', str_replace($main_folder, '', $folder), -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
}
$values = array();
foreach($comics_series as $pair){
$values[] = "('".mysql_real_escape_string($pair[0])."', '".((int) $pair[1])."')";
}
$check_query = mysql_query("SELECT * FROM comics WHERE name='".$values[0]."' AND issue='".$values[1]."'");
if ($check_query == '0'){
$query = 'INSERT INTO comics (name, issue) VALUES '.implode(',', $values);
$result = mysql_query($query);
echo ($result) ? 'Inserted successfully' : 'Failed to insert the values';
}
?>
is that the right format for the query_check?

<?php
$main_folder = './Comics'; // should be K:\Comics\ but I changed it because of the highlighting issue
$folders = glob($main_folder.'* [0-9]*', GLOB_ONLYDIR);
$comics_series = array();
foreach($folders as $folder){
$comics_series[] = preg_split('/(.+)\s(\d+)/', str_replace($main_folder, '', $folder), -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
}
$values = array();
foreach($comics_series as $pair){
$values[] = "('".mysql_real_escape_string($pair[0])."', '".((int) $pair[1])."')";
}
$query = 'INSERT INTO comics (name, issue) VALUES '.implode(',', $values);
$result = mysql_query($query);
echo ($result) ? 'Inserted successfully' : 'Failed to insert the values';
?>

If you are just stuck on splitting the comic name plus issue, check out the explode function
If you are struggling with file/folder traversal, I suggest taking a look at glob. It's much easier.
<?php
if ($handle = opendir('K:\Comics')) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
$comicName = null;
$pieces = explode(' ', $file); // explode the $file
// if the last element is a number..
if(is_numeric(end($pieces))) {
$comicIssue = end($pieces); // set the issue to a variable
array_pop($pieces); // remove the last element of the array
// loop through the rest of the array and put the pieces back together
foreach($pieces as $value) {
$comicName .= " $value"; // append the next array element to $comicName
}
} else {
echo "not issue number";
}
}
}
closedir($handle);
}
?>

Related

Passing Array values into Function

I am trying to pass an array value into a function, but can't seem to get it to work. Here is what I am trying to do
I have a folder on my server called /Rpt
The /Rpt folder has a bunch of different folders inside of it (30 of them) - these folders contain a bunch of different files in them
I want to check most of the folders in /Rpt, and get the name and date of the latest file (based on last modified or created date) ... i want to store the results into an array, that has (folder path, file name of last file, file date of last file)
This query gets the folders that need to be checked
$sql = "my SQL here";
$stmt = $dbh->prepare($sql);
$stmt->execute();
$arrValues = $stmt->fetchAll(PDO::FETCH_ASSOC);
This is a function that checks the specified folder, and displays the info i need (folder path, file name, file date)
function GetFileNameDate($location, $file_name, $file_date) {
$files = scandir($location);
$path = $location;
foreach ($files as $file) {
if (strpos($file, " ") !== false) {
$filename = $file;
$last_updated = date ("F d Y H:i:s", filemtime($path.'\\'.$file));
$results = array($filename=>$last_updated);
$file_name = key($results);
$file_date = reset($results);
return array($location, $file_name, $file_date);
}
}
}
When i call the function - and enter a specific path link in this example, it works OK and i shows the values i want to see
$FileNameDate = GetFileNameDate('E:\Rpt\FolderA');
echo $FileNameDate[0];
echo $FileNameDate[1];
echo $FileNameDate[2];
echo "<br/><br/>";
This is where I am having problems
I am trying to pass an array (list of folders from my SQL query) into the function, so i can output the (folder path, name of latest file, date of latest file) for each of the folders from SQL query
When i echo $locations (it lists all the folders which i am trying to pass to the function)
foreach ($arrValues as $row){
$locations = array($row['Folder']);
$FileNameDate = GetFileNameDate($locations);
echo $FileNameDate[0];
echo $FileNameDate[1];
echo $FileNameDate[2];
}
As per suggestion from #lovelace I also tried the following, but again just a blank page.
foreach ($arrValues as $row){
$locations = array($row['Folder']);
foreach ($locations as $FolderPath) {
$FileNameDate = GetFileNameDate($FolderPath);
echo $FileNameDate[0];
echo $FileNameDate[1];
echo $FileNameDate[2];
}
}
SOLUTION
see comment below to how above was fixed ... however I ended up implementing what i wanted a different way, sharing it in case anyone else needs similar functionality
function GetFileNameDate($location) {
$files = scandir($location);
$path = $location;
foreach ($files as $file) {
$iterator = new DirectoryIterator($path);
$mtime = 0;
$file = "";
foreach ($iterator as $fileinfo) {
if ($fileinfo->isFile()) {
if ($fileinfo->getMTime() > $mtime) {
$file = $fileinfo->getFilename();
$mtime = $fileinfo->getMTime();
}
}
}
return array($path, $file, $mtime);
}
}
foreach ($arrValues as $row){
$locations = array(rtrim($row['Folder']));
foreach ($locations as $FolderPath) {
$FileNameDate = GetFileNameDate($FolderPath);
echo $FileNameDate[0]; #folder
echo $FileNameDate[1]; #file
echo $FileNameDate[2]; #date
}
}

How to delete folder with images and mysql record news that does not exist

How to delete folder with images and mysql record news that does not exist?
Dont work. Why?
$resnotid = mysqli_query($db, "SELECT id FROM objects");
$idarray[] = array();
$namefolderarray[] = array();
while($rownotid = mysqli_fetch_array($resnotid)) {
$idarray[] = $rownotid['id'];
}
$dir = opendir('upload');
while($folder = readdir($dir)) {
if (is_dir('upload/'.$folder) && $folder != '.' && $folder != '..') {
$namefolderarray[] = $folder;
}
}
$delid = array_diff($namefolderarray, $idarray);
rmdir('upload/'.$delid.'/');
The method array_diff returns an array. So you have to iterate over that array.
$del_arr = array_diff($namefolderarray, $idarray);
foreach ($del_arr as $delid) {
rmdir('upload/'.$delid.'/');
}
Update 1
The previous solution only works for empty folders. If you have any content in the folders you must first delete the content. This can be done with an recursive function that iterates over the contents.
function rmdir_recursively($path) {
if (is_dir($path)){
$list = glob($path.'*', GLOB_MARK);
foreach($list as $item) {
rmdir_recursively($item);
}
rmdir($path);
} else if (is_file($path)) {
unlink($path);
}
}
$del_arr = array_diff($namefolderarray, $idarray);
foreach ($del_arr as $del_id) {
rmdir_recursively('upload/'.$del_id.'/');
}
Update 2
To also delete the database-records without a folder you can extend the code like this:
foreach ($del_arr as $del_id) {
rmdir_recursively('upload/'.$del_id.'/');
$del_id_escaped = mysqli_real_escape_string($del_id);
mysqli_query($db, "DELETE FROM objects WHERE id='$del_id_escaped'");
}

Convert Recursive Directory Listing to MySQL Table

I need to list all files/folders in a given parent folder, and dump it out to mysql.
So far I have:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$dir = '/home/kevinpirnie/www';
function dirToArray( $dir ) {
$result = array();
$cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value, array(".", ".."))) {
if (is_dir($dir . DIRECTORY_SEPARATOR . $value)){
$result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value);
} else {
$result[] = $value;
}
}
}
return $result;
}
$res = dirToArray($dir);
echo '<hr />';
echo '<pre>';
print_r($res);
echo '</pre>';
What I am stuck on is how I can assign ID's to the directories, and then associate them with their parent ID's.
Right now, this code sort of does what I need it to, I just need to be able to convert it to mysql insert statements, yet keep the associative structure, and I am braindead from a long long week of work.
In the end, I am looking to have a table structure similar to:
FileID, FolderID, ParentFolderID, FileName
How can I do this?
try something like this:
function dirToDb($res, $parentId = 0)
{
foreach ($res as $key => $value) {
if (is_array($value)) {
$db->exec("insert into table (path, parentId) VALUES (?, ?)", [$key, $parentId]);
dirToDb($value, $db->fetch("SELECT LAST_INSERT_ID()"));
} else {
$db->exec("insert into table (path, parentId) VALUES (?, ?)", [$value, $parentId]);
}
}
}
$res = dirToArray($dir);
dirToDb($res);
I have modified your code a little. Now for every directory,
index 0 point to directory index
index 1 point to parent directory index
index 2,3,....n points to files
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$dir = '/home/kevinpirnie/www';
$GLOBALS['I'] = 0; // root folder given index 0
function dirToArray( $dir , $parent) {
$result = array();
$cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value, array(".", ".."))) {
if (is_dir($dir . DIRECTORY_SEPARATOR . $value)){
$result[$value] = [++$GLOBALS['I']]; // add folder index
$result[$value][] = $parent; // add parent folder index
$result[$value][] = dirToArray($dir . DIRECTORY_SEPARATOR . $value, $GLOBALS['I']);
} else {
$result[] = $value;
}
}
}
return $result;
}
$res = dirToArray($dir, $GLOBALS['I']);
echo '<hr />';
echo '<pre>';
print_r($res);
echo '</pre>';
echo '</pre>';
You can now insert the data into mysql tables directly using a similar recursive loop (if you do not want to use mysql auto generated id)
If you want to use auto generated mysql id, you should do insertion in two passes. In first pass insert the folder data and get the id from mysql insert id function. Then create an associative array map
$array_map[$current_folder_id] = mysqli_insert_id()
Then update this id in the second recursive pass
I think you need to insert folder names too as records into the DB, otherwise you wont get parent ID. But, in your result the folder names are missing as record items. I modified your code with assumption that you don't need the result as array but the SQL statement only.
<?php
$qry = array();
$result = $conn->query("SELECT MAX(FileID) as lastid FROM YOUR-TABLE-NAME-HERE");
$row = $result->fetch_assoc();
$id = $row['lastid'];
function dirToSql($dir, $parent) {
global $qry;
global $id;
$result = array();
$cdir = scandir($dir);
foreach($cdir as $key => $value) {
if(!in_array($value, array('.', '..'))) {
$id++;
$qry[] = "('".$id."', '".$dir."', '".$parent."', '".$value."')";
if(is_dir($dir . DIRECTORY_SEPERATOR . $value)) {
dirToSql($dir . DIRECTORY_SEPERATOR . $value, $id);
}
}
}
return $qry;
}
$dir = '/home/kevinpirnie/www';
$sql = dirToSql($dir, 0);
//Here is your SQL Statement
echo $qry = "INSERT INTO YOUR-TABLE-NAME-HERE (`FileID`, `FolderID`, `ParentFolderID`, `FileName`) VALUES ".implode(',', $sql);
You can optimize the code & the query if needed
Every row in your Mysql directory table has three columns -
Directory Id, Directory name, parent id
For each insert the parent id will specify the parent of current directory in a row. For the Root directory parent id is 0
A really useful way to structure your database is with nested sets. Joomla uses this for things like article categories. These can be infinitely nested under one another.
enter link description here

How to find similarity between IDs string and filenames?

I have a list of IDs
$Ids="1201,1240,1511,1631,1663,1666,1716,2067,2095";
and in the /imgs/ folder there are many jpg filenames related to these IDs. But there are a lot of IDs that do not have any image.
for example there are in the /imgs/
1201_73.jpg
1201_2897.jpg
1240-9834.jpg
1240-24.jpg
1511-dsc984.jpg
1511-dsc34.jpg
What I want to achieve is to find which of the IDs have images in the img folder.
Thank you
Updated
$array = array();
$foo = explode('.jpg', $images);
foreach($foo as $id) {
$digi = substr(trim($id), 0,4);
if(!in_array($digi, $array)) {
array_push($array, $digi);
echo $id . ".jpg <br/>";
$where .= "id='$digi' or ";
}
}
First, turn your string of IDs into an array.
$idsArray = explode(',', $Ids);
Now iterate through the directory, checking each file to see if it starts with the ID.
$hasImages = array();
foreach (new DirectoryIterator(__DIR__ . '/imgs') as $fileInfo) {
if ($fileInfo->isDot() || $fileInfo->isDir()) {
continue;
}
foreach ($idsArray as $id) {
if (0 === strpos($fileInfo->getBasename(), $id)) {
$hasImages[] = $id;
break;
}
}
}
$hasImages = array_unique($hasImages);
$hasImages will contain an array of IDs which have an image.
Something like this should work:
$files = glob('/imgPath/*.jpg');
$hasImage = array_unique(array_map(function($file) {
return explode('-', $file)[0];
}, $files));
$withimages= array_diff(explode($Ids), $hasImage);

Compare directory contents to database column in Joomla

I have a directory with images and I need to check a specific column of a table in my joomla database to see which files exist in the directory but not in the database and delete them.
What I've tried so far has not worked at all
my code is this
$dir = 'directory/of/files';
$files1 = scandir($dir);
$db =& JFactory::getDBO();
$query = "SELECT image FROM #__tablename WHERE something LIKE 'something else'";
$db->setQuery($query);
$result = $db->loadResultArray();
foreach ( $files1 as $file ) {
if (stripos($result, $file) === false) {echo 'file '.$file.' does not exist in database '; unlink($dir.$file);}
else {echo 'file '.$file.' exists in db ';}
}
Any ideas?
Thank you in advance
You problem is that in if(stripos($result, $file)), $result is an array, not a string. Turn on error reporting in the Joomla Configuration to see this. You should be seeing a message like:
Warning: stripos() expects parameter 1 to be string
However, I recommend the following change as it is a bit cleaner:
$dir = 'directory/of/files';
$files1 = scandir($dir);
$db = JFactory::getDBO();
$query = "SELECT image FROM #__tablename WHERE something LIKE 'something else'";
$db->setQuery($query);
$result = $db->loadResultArray();
$diff = array_diff($files1, $result);
// print_r($diff);die;
foreach ( $diff as $file ) {
unlink($dir.$file);
}
Uncomment the print_r first to check it is what you want.
This is the code that I finally managed to write and do what I need
$preImagePath = 'some/path/';
$fullImagePath = $params->get('extra1');//more of the path
$value = $params->get('extra3');
$initfile = scandir($preImagePath.$fullImagePath);
$files1 = array_diff($initfile, array('.', '..'));
$db =& JFactory::getDBO();
$query = "SELECT image FROM #__table WHERE column LIKE '".$value."'";
$db->setQuery($query);
$results = $db->loadObjectList();
foreach ( $results as $result ) {
$imagearray .= $result->image.' ';
}
foreach ( $files1 as $file ) {
if (strpos($imagearray, $fullImagePath.$file) === false) { unlink($preImagePath.$fullImagePath.$file); }
}

Categories