API Google Диска — PHP — Рекурсивно Получает все Содержимое Папок И Выводит Их В Виде Не Вложенного Массива

#php #recursion #multidimensional-array #google-drive-api

Вопрос:

Я хочу клонировать папку Google Диска и все ее содержимое с помощью PHP API Google. После небольшого копания, публикации и последующего перечитывания я понимаю, что API привода (V3) четко указывает:

«Папки не могут быть скопированы».

введите описание изображения здесь

Итак, мой план состоит в том, чтобы:

  1. Рекурсивно пройдитесь по соответствующему идентификатору папки Google Диска и выведите ее содержимое в виде массива
  2. Создайте новую destination папку на диске
  3. Выполните цикл через вышеупомянутый массив и на основе типа 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;
}