ivanvermeyen / laravel-google-drive-demo

Laravel & Google Drive Storage - Demo project with Laravel 5.4
405 stars 155 forks source link

Create and add some file to a known directory #23

Closed ClaudiaCF closed 6 years ago

ClaudiaCF commented 6 years ago

Sorry for asking again, but i'm new to this and maybe what i'm asking is something you already know the answer to. I want to do something like the "put-in-dir" route, but sending the folder id in which i want my file and also some text that i want to put in the file. for example -> i have a json object with some properties (name and surname) and when i click a button, i want to create a txt file with that properties in an specified folder id. My problem is that i don't know how to send to the route the id and those properties without sending it as a parameters in the url.

ivanvermeyen commented 6 years ago

Hi,

I'm not 100% clear on your situation, but what comes to mind right now are 2 possibilities:

Does that help?

ClaudiaCF commented 6 years ago

what i want to do is something like this: in the front-end, y pass in a POST call the folderId

axios.post('http://localhost:9005/create-dir/', { FolderId: folderId, Text: text })
        .then(function (response) {
          console.log('saved successfully')
        })

and then the route i want to do would be something like (i'll be writing pseudo-code because i'm not really sure how to get the parameters from the post)

Route::post('put-in-dir/', function() {
    $folderId = $_REQUEST.FolderId; //get from that request the value, i'm not sure how
    $text = $_REQUEST.Text; //same as above

    Storage::cloud()->makeDirectory($folderId.'/folder'); //create a folder inside the known folder
    //then get somehow the path of the folder that i just created, let's call it "folderId2"
    Storage::cloud()->put($folderId2.'/test.txt', $text); //generate file inside the folder with the text i sent with the POST

    return 'File was created in the sub directory in Google Drive';
});
ivanvermeyen commented 6 years ago

There are a few ways to get the request input in Laravel. I mostly use the helper function:

$folderId = request('FolderId');
$text = request('Text');

With this, you should be able to create the new folder:

$newFolderName = 'folder';

Storage::cloud()->makeDirectory($folderId.'/'.$newFolderName);

Now as far as I know there is no easy way to get the newly created folder ID. So in the examples I used this approach: (but beware for duplicate names)

$newFolder = $contents->where('type', '=', 'dir')
    ->where('filename', '=', $newFolderName)
    ->first();

$folderId2 = $newFolder['basename'];

Now you can upload the file to the new folder with the text in it:

Storage::cloud()->put($folderId2.'/test.txt', $text);
ClaudiaCF commented 6 years ago

ok thank you so much!!!

ClaudiaCF commented 6 years ago

i'm doing that because i'm doing some kind of e-mail managers that lets you save your email in Google Drive, with its attachments my code is something like this

Route::post('put-in-dir/', function(Request $request) {

    $folderId = $request->get('FolderId');
    $to = $request->get('To');
    $from = $request->get('From');
    $ref = $request->get('Reference');
    $attachsRaw = $request->get('attachsRaw');

    Storage::cloud()->makeDirectory($folderId.'/'.$ref);

    $contents = collect(Storage::cloud()->listFolderContents($folderId));

    $newFolder = $contents->where('type', '=', 'dir')
    ->where('filename', '=', $ref)
    ->first();

    $folderId2 = $newFolder['path'];
    foreach($attachsRaw as $att)
    Storage::cloud()->put($folderId2.'/whatever.txt', $att);

    return 'File was created in the sub directory in Google Drive';
});

and i get an error when i try to the line Storage::cloud()->put($folderId2.'/whatever.txt', $att); because my list attachsRaw has VERY large strings with the encondings of the attachments, i think its the same problem you mention in the get-put-stream route

so i want to do the 'put' of the file without having that error, do you know how? in the put-get stream you mention Storage::cloud()->put($filename, fopen($filePath, 'r+')); but i don't have any file to upload, i just know the title and extension of the file and what i want to put inside

ivanvermeyen commented 6 years ago

Is $attachsRaw not an array of uploaded files/attachments?

ClaudiaCF commented 6 years ago

no, $attachsRaw is a list that contains for every attachment its name ('whatever.jpg') and its raw (that is a very large string) and i don't know if it works that way but i think that having those properties, for example if my attachment is a pdf, i could just Storage::cloud()->put($folderId2.'/whatever.pdf', $rawString); the problem when is that when i try to send the list, it gives me an error because of the "raw" field (i suppose it is for the size)7 so i think is like the put-get-stream example but in that example you open a file that already exists, in this one i want to create it when i send the parameters in the request

ClaudiaCF commented 6 years ago

it would be the 'data' field here: https://developers.google.com/gmail/api/v1/reference/users/messages/attachments#resource

ivanvermeyen commented 6 years ago

After some Googling, I found that you can create a stream from a base64 encoded string:

This is an example of the data:// approach from the PHP docs:

$data = urlencode('Some string');
$fp = fopen('data:text/plain,'.$data, 'rb'); // urlencoded data 
// or...
$data = base64_encode($data);
$fp = fopen('data:text/plain;base64,'.$data, 'rb'); // base64 encoded data 

Note from the docs:

Windows offers a text-mode translation flag ('t') which will transparently translate \n to \r\n when working with the file. In contrast, you can also use 'b' to force binary mode, which will not translate your data. To use these flags, specify either 'b' or 't' as the last character of the mode parameter. ... If you do not specify the 'b' flag when working with binary files, you may experience strange problems with your data, including broken image files and strange problems with \r\n characters. ... For portability, it is strongly recommended that you always use the 'b' flag when opening files with fopen().

The second example in the blog post also creates a stream from any string, but I'm not sure how to use the actual stream with Laravel's Storage::put().

$string = 'Some bad-ass string';

$stream = fopen('php://memory','r+');
fwrite($stream, $string);
rewind($stream);

echo stream_get_contents($stream);

Let me know if any of this works, I'm curious :)

ClaudiaCF commented 6 years ago

But the problem isn't in the enconding, what i'm doing is (in javascript) get the raw base64 email, decode it and then i want to receive it in my api (it's a string representing an eml file, so it's very large) and there is no problem in sending it in the request but at the moment when i try to do Storage::cloud()->put($folder.'/whatever.eml', $largeString); it gaves me this error: image image maybe i can do it your way but i think its easier to decode it in javascript and send to the API the string i really need

ClaudiaCF commented 6 years ago

and altough it says 'wrong url for upload' i can assure you that if a put a little string instead of the eml text, it works

ivanvermeyen commented 6 years ago

Ok I see what you're trying to do now. Weird that it's complaining about the upload url... Does it work if you save it to a local file?

If you think a stream would help, I think you can do:

$stream = fopen('data:text/plain,'.$largeString, 'rb');
Storage::cloud()->put($folder.'/whatever.eml', $stream);
ClaudiaCF commented 6 years ago

it works :) thank so much again, i hope it's the last time i have to ask you something haha i can't thank you enough!!!

ivanvermeyen commented 6 years ago

No worries 👍