Home > other >  Google Drive API - PHP - Get all Folder Contents Recursively & Output As A Non-nested Array
Google Drive API - PHP - Get all Folder Contents Recursively & Output As A Non-nested Array

Time:10-02

I want to clone a Google Drive folder & all of its contents via Google's PHP API. After a bit of digging, posting, & then re-reading, I understand that enter image description here

So, my plan is to:

  1. Recursively traverse a respective Google Drive Folder ID & output its contents as an array
  2. Create a new destination Drive Folder
  3. Loop through the aforementioned array & based on the MIME type A) if a folder, create a new folder in my destination folder from my source parent folder B) if it's not a folder, copy the file C) loop again to move files / folders in my destination folder based on the original parents value(s).

What I have:

  • The API call all set up and a first pass of a recursive function that lists all of the folders / files

Where I'm getting stuck:

  • The tree/array I'm building creates a multidmensional/nested array, when I want it to be a single dimensional array
  • Every time I try to flatten my array to 'one level' it flattens everything down too much

My Question:

  • How can I create a recursive function that traverses all files/folders, but outputs into an array without nesting?

My code:

// 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 (&$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) "###"
}
}

My desired 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) "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"
    }
}

CodePudding user response:

You have to remove $files_arr = array(); from your function because you have already initialize out of function and dont assign return value to $files_array of your recursive function.

your function will look like that

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;

}

CodePudding user response:

I made a few tweaks and have things 'working'. Specifically:

  • I'm adding child folder items to an array that passes into the function via arugment instead of setting it within the function (i.e. populating an array outside of the function as opposed to populating an array set within the funciton)
  • I added an inner loop to add recursive child content items to the array as opposed to adding the entire recursive function output to the array
  • To prevent duplicates I'm making sure I set the file id as the array key

I feel like my solution is unelegant and nonperformant (improvements definitely welcome!), but I did test until 5 folder levels deep and it's working the way I need it to.

My updated code:

// 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;
}
  • Related