Search code examples
phpapigoogle-cloud-platformgoogle-cloud-storagefopen

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


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.


Solution

  • 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