0

I have a permissions problem trying to download a file from Google Cloud Storage using PHP in an API method that receives a call from an App.

To make sure, I created a service account, assigned the role of administrator and used the .json file with the keys of this service account to authenticate when creating the Storage client. Then in the call I pass by parameters the data of the file (which I have published just in case) and the route, but it doesn't matter which route you try always leaves the same error.

The code of my App that affects this method is:

<?php
use Silex\Application;
use Silex\Provider\TwigServiceProvider;
use Symfony\Component\HttpFoundation\Request;
use Google\Cloud\Storage\StorageClient;


// Crea la aplicacion de SILEX
$app = new Application();


//Descarga el archivo seleccionado de un siniestro.
$app->get('/download_archivos_siniestro_app', function () use ($app) {

    $ARCH=$_REQUEST['Archivo'];
    $destination=$_REQUEST['Ruta'];


    require __DIR__ . '/vendor/autoload.php'; 

    $path = "credenciales.json";
    $keyFile = json_decode(file_get_contents($path), true);
    $projectId = "mi_ID_del_proyecto";

    $storage = new StorageClient($config = ['projectId' => $projectId, $keyFile]);

    $bucketName = "mi_bucket";
    $objectName = $ARCH;

    $bucket = $storage->bucket($bucketName);
    $object = $bucket->object($objectName);
    $object->downloadToFile(__DIR__ .$destination);

    $respuesta=array();
    $respuesta['status']='0';
    $respuesta['message']='Todo correcto!';
        }
    }
    return $app->json($respuesta);
});


// Funcion para devolver la instancia del PDO
$app['database'] = function () use ($app) {
    // Connect to CloudSQL from App Engine.
    $dsn = getenv('MYSQL_DSN');
    $user = getenv('MYSQL_USER');
    $password = getenv('MYSQL_PASSWORD');
    if (!isset($dsn, $user) || false === $password) {
        throw new Exception('Set MYSQL_DSN, MYSQL_USER, and MYSQL_PASSWORD environment variables');
    }

    $db = new PDO($dsn, $user, $password);

    return $db;
};


// Acepta peticiones JSON
$app->before(function (Request $request) {
    if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
        $data = json_decode($request->getContent(), true);
        $request->request->replace(is_array($data) ? $data : array());
    }
});

return $app;
?>

When I send the file and destination parameters on the call, I do it this way:

https://midominiodegoogle.appspot.com/download_archivos_siniestro_app?Archivo=image.jpg&Ruta=/image.jpg

Once this call is made, I receive the following error in the console log:

"PHP message: PHP Warning:  fopen(/app/image.jpg): failed to open stream: Permission denied in /app/vendor/google/cloud/src/Storage/StorageObject.php on line 585"

The other API methods work without problem, errors simply come from not being able to place the file you are trying to download in any of the specified folders.

Thanks in advance for the help.

Frampe
  • 13
  • 2
  • Possible duplicate of this. https://stackoverflow.com/q/3882244/10417503 Try changing the folder permissions. – Arun Karthick Nov 22 '19 at 12:07
  • The fact is that by "deploying" the App, the "app" folder is created within Google Cloud, which I think I cannot access to change permissions. I was trying to point out of that folder somehow but I can't. – Frampe Nov 22 '19 at 12:24

2 Answers2

0

For the service account Storage Admin role will not work you need a role called Storage Object Admin. I know it is confusing.

Bonus Tip: As a best practice you should never give admin permissions to your service accounts. You should use either objectCreator or objectViewer depending on whether you want to create or view the files in the bucket

GCP Role selector screen

Kunal Deo
  • 2,248
  • 2
  • 18
  • 27
  • The service account had all those roles, as I was not sure which to assign it I decided to put all the related ones to do the tests. I have removed all except Storage Object Adminas you said and still not working. Thank you very much for the bonus tip, I will do so from now on. – Frampe Nov 26 '19 at 09:31
0

In App Engine, in order to store files, you should use Cloud Storage. Quoting the documentation:

If your PHP 7 app needs to read and write files during runtime, or serve files such as movies, images or other static content, we recommend you use a Cloud Storage bucket

However, if your needs require a file to appear as if it's in local disk for a specific reason, you should be able to do so storing it in the /tmp directory. You can find more info, as well as a code snippet in the Reading and Writing Temporary Files docs

Jose V
  • 1,356
  • 1
  • 4
  • 12