#php #recursion #multidimensional-array #google-drive-api
Вопрос:
Я хочу клонировать папку Google Диска и все ее содержимое с помощью PHP API Google. После небольшого копания, публикации и последующего перечитывания я понимаю, что API привода (V3) четко указывает:
«Папки не могут быть скопированы».
Итак, мой план состоит в том, чтобы:
- Рекурсивно пройдитесь по соответствующему идентификатору папки Google Диска и выведите ее содержимое в виде массива
- Создайте новую
destination
папку на диске - Выполните цикл через вышеупомянутый массив и на основе типа MIME A) если папка, создайте новую папку в моей
destination
папке из моейsource
родительской папки B) если это не папка, скопируйте файл C) повторите цикл, чтобы переместить файлы / папки в моюdestination
папку на основе исходногоparents
значения(значений).
Что у меня есть:
- Вызов API полностью настроен и первый проход рекурсивной функции, в которой перечислены все папки / файлы
Где я застрял:
- Дерево/массив, который я строю, создает многомерный/вложенный массив, когда я хочу, чтобы он был одномерным массивом
- Каждый раз, когда я пытаюсь выровнять свой массив до «одного уровня», он слишком сильно выравнивает все
Мой Вопрос:
- Как я могу создать рекурсивную функцию, которая обходит все файлы/папки, но выводит данные в массив без вложенности?
Мой код:
// Getting the Drive Files
// $copy_from_id = My 'source' Drive Folder
$driveService = new Google_Service_Drive($client);
$optParams = array(
'fields' => 'nextPageToken, files(*)',
'q' => "'$copy_from_id' in parents"
);
$files_arr = array();
$results = $driveService->files->listFiles($optParams);
if (count($results->getFiles()) !== 0) {
$files = $results->getFiles();
$files_arr = $this->recursivelyGetGDriveFolderContents($driveService, $files);
return $files_arr;
/*
* The code below flattens things 'too much',
* i.e. it's only a 1:1 array, when I really one a 'one-
* level-deep' multidimensional array where the values are an
* array. Plus I feel like I'm getting something wrong in my
* recursive function to begin with and should probably try
* to fix it there as opposed to processing again aftewards.
*/
// $result = array();
// array_walk_recursive($files_arr,function($v) use (amp;$result){ $result[] = $v; });
}
// My recursive function
function recursivelyGetGDriveFolderContents($driveService, $files){
$files_arr = array();
foreach ($files as $file) {
$file_id = $file->getId();
$file_name = $file->getName();
$file_type = $file->getMimeType();
$file_parents = $file->getParents();
$files_arr[] = array(
'file_name' => $file_name,
'file_type' => $file_type,
'file_parents' => $file_parents,
'file_id' => $file_id,
);
if($file_type == 'application/vnd.google-apps.folder'){
$optParams = array(
'fields' => 'nextPageToken, files(*)',
'q' => "'$file_id' in parents"
);
$results = $driveService->files->listFiles($optParams);
if (count($results->getFiles()) !== 0) {
$files_sub = $results->getFiles();
// I feel like this is the problem, this is causing nesting when I don't want it to
$files_arr[] = $this->recursivelyGetGDriveFolderContents($driveService, $files_sub);
}
}
}
return $files_arr;
}
My current array
array(4) {
[0]=>
array(4) {
["file_name"]=>
string(4) "D1L1"
["file_type"]=>
string(36) "application/vnd.google-apps.document"
["file_parents"]=>
array(1) {
[0]=>
string(33) "###"
}
["file_id"]=>
string(44) "###"
}
[1]=>
array(4) {
["file_name"]=>
string(4) "F2L1"
["file_type"]=>
string(34) "application/vnd.google-apps.folder"
["file_parents"]=>
array(1) {
[0]=>
string(33) "###"
}
["file_id"]=>
string(33) "###"
}
[2]=>
array(2) {
[0]=>
array(4) {
["file_name"]=>
string(4) "D1L2"
["file_type"]=>
string(36) "application/vnd.google-apps.document"
["file_parents"]=>
array(1) {
[0]=>
string(33) "###"
}
["file_id"]=>
string(44) "###"
}
[1]=>
array(4) {
["file_name"]=>
string(4) "F1L2"
["file_type"]=>
string(34) "application/vnd.google-apps.folder"
["file_parents"]=>
array(1) {
[0]=>
string(33) "###"
}
["file_id"]=>
string(33) "###"
}
}
[3]=>
array(4) {
["file_name"]=>
string(4) "F1L1"
["file_type"]=>
string(34) "application/vnd.google-apps.folder"
["file_parents"]=>
array(1) {
[0]=>
string(33) "###"
}
["file_id"]=>
string(33) "###"
}
}
Мой желаемый массив
array(4) {
[0]=>
array(4) {
["file_name"]=>
string(4) "D1L1"
["file_type"]=>
string(36) "application/vnd.google-apps.document"
["file_parents"]=>
array(1) {
[0]=>
string(33) "1QsJXE_YfGIREOeD7VamzKn9_qsF__hFj"
}
["file_id"]=>
string(44) "1uyQbe4IHRppwuqWOAatiJtygISAXEqFZtyOKzp7qNW8"
}
[1]=>
array(4) {
["file_name"]=>
string(4) "F2L1"
["file_type"]=>
string(34) "application/vnd.google-apps.folder"
["file_parents"]=>
array(1) {
[0]=>
string(33) "1QsJXE_YfGIREOeD7VamzKn9_qsF__hFj"
}
["file_id"]=>
string(33) "1GY34PRVDU5yFXSGjYtwg_g7DoWdXWxab"
}
[2]=>
array(4) {
["file_name"]=>
string(4) "D1L2"
["file_type"]=>
string(36) "application/vnd.google-apps.document"
["file_parents"]=>
array(1) {
[0]=>
string(33) "1GY34PRVDU5yFXSGjYtwg_g7DoWdXWxab"
}
["file_id"]=>
string(44) "1oFLiM9TKHB2JQQOrFMBIQGjQnexRfFADk-x1ro07nKg"
}
[3]=>
array(4) {
["file_name"]=>
string(4) "F1L2"
["file_type"]=>
string(34) "application/vnd.google-apps.folder"
["file_parents"]=>
array(1) {
[0]=>
string(33) "1GY34PRVDU5yFXSGjYtwg_g7DoWdXWxab"
}
["file_id"]=>
string(33) "1TCUuNkPPzy1L-q5hS-obUdMlGrtDELAJ"
}
[4]=>
array(4) {
["file_name"]=>
string(4) "F1L1"
["file_type"]=>
string(34) "application/vnd.google-apps.folder"
["file_parents"]=>
array(1) {
[0]=>
string(33) "1QsJXE_YfGIREOeD7VamzKn9_qsF__hFj"
}
["file_id"]=>
string(33) "1JsI9kgESKQbKpaTWUwLDSFpj1VJPUuXL"
}
}
Ответ №1:
Вам необходимо удалить $files_arr = array(); из вашей функции, потому что вы уже инициализировали выход из функции и не присваиваете возвращаемое значение $files_array вашей рекурсивной функции.
ваша функция будет выглядеть так
function recursivelyGetGDriveFolderContents($driveService, $files){
foreach ($files as $file) {
$file_id = $file->getId();
$file_name = $file->getName();
$file_type = $file->getMimeType();
$file_parents = $file->getParents();
$files_arr[] = array(
'file_name' => $file_name,
'file_type' => $file_type,
'file_parents' => $file_parents,
'file_id' => $file_id,
);
if($file_type == 'application/vnd.google-apps.folder'){
$optParams = array(
'fields' => 'nextPageToken, files(*)',
'q' => "'$file_id' in parents"
);
$results = $driveService->files->listFiles($optParams);
if (count($results->getFiles()) !== 0) {
$files_sub = $results->getFiles();
//i have remove array assign
$this->recursivelyGetGDriveFolders($driveService, $files_sub);
}
}
}
return $files_arr;
}
Комментарии:
1. Спасибо, Форамкумар! На самом деле я действительно пытался это сделать, но когда я это делаю, я не получаю содержимого папок на диске выше первого уровня (т. Е. Выше не выводится содержимое папок, вложенных в папку дочернего диска).
2. попробуйте функцию array push для добавления данных. Может быть, это решит вашу проблему.
Ответ №2:
Я сделал несколько настроек, и все «работает». Конкретно:
- Я добавляю элементы дочерних папок в массив, который переходит в функцию через arugment, вместо того, чтобы устанавливать его внутри функции (т. Е. Заполнять массив вне функции, а не заполнять массив, установленный в функции)
- Я добавил внутренний цикл для добавления рекурсивных дочерних элементов содержимого в массив, в отличие от добавления всего вывода рекурсивной функции в массив
- Чтобы предотвратить дубликаты, я обязательно устанавливаю идентификатор файла в качестве ключа массива
Я чувствую, что мое решение неэлегантно и неэффективно (улучшения определенно приветствуются!), Но я тестировал до глубины 5 уровней папок, и оно работает так, как мне нужно.
Мой обновленный код:
// Getting the Drive Files
// $copy_from_id = My 'source' Drive Folder
$driveService = new Google_Service_Drive($client);
$optParams = array(
'fields' => 'nextPageToken, files(*)',
'q' => "'$copy_from_id' in parents"
);
$files_arr = array();
$results = $driveService->files->listFiles($optParams);
if (count($results->getFiles()) !== 0) {
$files = $results->getFiles();
$files_arr = $this->recursivelyGetGDriveFolderContents($driveService, $files);
return $files_arr;
}
// My recursive function
function recursivelyGetGDriveFolderContents($files_arr, $driveService, $files){
// Instead of setting my main array in this function I pass data into it via the function argument
foreach ($files as $file) {
$file_id = $file->getId();
$file_name = $file->getName();
$file_type = $file->getMimeType();
$file_parents = $file->getParents();
$return_file = array(
'file_name' => $file_name,
'file_type' => $file_type,
'file_parents' => $file_parents,
'file_id' => $file_id,
);
$files_arr[$file_id] = $return_file;
if($file_type == 'application/vnd.google-apps.folder'){
$optParams = array(
'fields' => 'nextPageToken, files(*)',
'q' => "'$file_id' in parents"
);
$results = $driveService->files->listFiles($optParams);
if (count($results->getFiles()) !== 0) {
$files_sub = $results->getFiles();
$files_sub_arr = $this->recursivelyGetGDriveFolderContents($files_arr, $driveService, $files_sub);
// I added this inner loop to add each child to the main parent array so that I didn't have nested arrays
foreach($files_sub_arr as $file_sub){
$file_sub_id = $file_sub['file_id'];
$files_arr[$file_sub_id] = $file_sub;
}
}
}
}
return $files_arr;
}