skip to Main Content

I’ve made a GCP cloud function in PHP8.1, that connects to GCP cloud storage. I receive a filename to be processed, and the cloud function should open the file, decode it, and send the result to a pub sub.

The problem I’m having is that I can’t get fopen to work on the file hosted in cloud storage.

I need fopen to work, because another package that I’m using to decode AVRO files uses fopen to access the file.

Thanks in advance for any help.

I’ve tested file_get_contents and that works fine.

I’ve also tested downloading the file contents as a stream using the cloud storage package, and that works fine as well.

I’ve also modified the allow_url_fopen php setting, but that didn’t change anything.

I’m using the google/cloud-storage package, version v1.30.2

I’m using the google/cloud package, version v0.201.0

$bucketName = 'bucket-name';
$filePath = 'file/path/in/bucket';

$this->storageClient->registerStreamWrapper();
$bucket = $this->storageClient->bucket($bucketName);
$object = $bucket->object($filePath);

$newGsFilePath = "gs://$bucketName/$filePath";

error_log(file_exists($newGsFilePath)); // logs "1", signifying that the file exists
error_log(file_get_contents($newGsFilePath)); // logs the contents of the file
$fp = fopen($newGsFilePath, "rb"); 
error_log(var_export($fp, true)); // logs "NULL". It should be false according to docs when it fails?
error_log(fseek($fp, 0, SEEK_SET)); // logs "-1", presumably because $fp is NULL
fclose($fp);

$stream = $object->downloadAsStream();
$contents = '';
while (!$stream->eof()) {
    $contents .= $stream->read(1024);
}

error_log("$contents: $contents"); // logs the contents of the file

Could it be a permissions issue? I’m not the admin of this account, and am fairly new to GCP

2

Answers


  1. Chosen as BEST ANSWER

    The files opened from a Google Cloud Storage are not seekable, that's why seek($fp, 0) returns -1.

    The file can be transformed into a seekable file by copying its contents into a local file, using

    file_put_contents('new/local/path/to.file', file_get_contents($newGsFilePath));
    

    I would recommend deleting the file after you are done with it.

    Thanks to @KoalaYoung for helping me come to this answer.


  2. If you don’t want to manage an extra file (or if you want to work within memory), you may try this:

    $bucketName = 'bucket-name';
    $filePath = 'file/path/in/bucket';
    
    $this->storageClient->registerStreamWrapper();
    $bucket = $this->storageClient->bucket($bucketName);
    $object = $bucket->object($filePath);
    
    $newGsFilePath = "gs://$bucketName/$filePath";
    
    $fp = fopen($newGsFilePath, 'rb');
    $cache = fopen('php://temp', 'wb+');
    stream_copy_to_stream($fp, $cache);
    fclose($fp);
    rewind($cache);
    
    // Use $cache instead of $fp
    // ...
    // ...
    

    The "php://temp" read-write stream would be created in-memory until it is larger than 2MB (or override the maxmemory like this: php://temp/maxmemory:16MB). If it is bigger, PHP will create and manage it as a temp file.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search