I created one folder and inside that folder I've created 2 text files, with some text inside. I can also list the files and get the text in them without problems. Now I am trying to update the text inside of that files, but I am always getting this error:
"domain": "global",
"reason": "fieldNotWritable",
"message": "The resource body includes fields which are not directly writable."
I created a function similar to the one presented in https://developers.google.com/drive/v2/reference/files/update.
I used this example because in version v3, Google don't present any example, and I can't find anything that can help me in this. My function is below.
function updateFile ($service, $fileId, $newTitle, $newDescription, $newMimeType, $text) {
try {
// First retrieve the file from the API.
$file = $service->files->get($fileId);
// File's new metadata.
$file->setName($newTitle);
$file->setDescription($newDescription);
$file->setMimeType($newMimeType);
// File's new content.
$additionalParams = array(
'data' => $text,
'uploadType' => 'media'
);
// Send the request to the API.
$updatedFile = $service->files->update($fileId, $file, $additionalParams);
return $updatedFile;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
Thank you in advance.
Based from this SO answer, on v3, using update like that throws the error fieldNotWritable.
The solution is to create an empty File setting only the new values:
File newContent = new File();
newContent.setTrashed(true);
service.files().update(fileId, newContent).execute();
Note: File refers to com.google.api.services.drive.model.File (it is not java.io.File).
Also, based from this documentation, you can see that shared isn't a writable field. You can share a file by adding a new permission, and you can check if a file has been shared by reading the shared property. But saying a file is shared, other than by actually sharing it, makes no sense. [Source.]
Related
I currently have a script which loops through a google drive folder and does various things, one of which is to sync files uploaded/updated on gdrive with the files on the server. The script decides it wants a file, and uses the following function to write it to the server:
function get_file($file, $service, $docroot, $area){
$errorthrown = false;
try {
$getFile = $service->files->get($file->id, array('alt' => 'media'));
$content = $getFile->getBody()->getContents();
$handle = fopen($docroot.'file/'.$area.'/'.$file->name,"w");
fwrite($handle, $content);
fclose($handle);
} catch (\Throwable $e) {
print "The Google Drive API threw an error, but dont worry, we'll come back for this.";
return "error";
}
}
Now I would like to offer a file manager on the server which allows users to pick files, including those on the server and those which aren't. Is there a way of forcing the download of files returned from the google drive API, without first fwrite()ing?, for example using readfile() or fpassthru()?
I have tried various things with readfile() but from google drive I have the file contents, but no path to the file itself.
Any ideas?
Thanks a lot.
How do I render without my controller attempting to load a non-existent .ctp file.
This is my code:
//without this, I get an error trying to load a non-existent .ctp file. When I include it, the browser does not render the PNG file.
$this->autoRender = false;
//... get avatar code
if (!file_exists($avatarPath))
throw new Exception('Could not find file: '.$avatarPath);
$file = file_get_contents($avatarPath);
header('Content-Type: image/png');
if ($file === false)
throw new Exception('file_get_contents failed on avatarPath');
else
echo $file;
When I use $this->autoRender = false;, the header call appears to be ignored. Any ideas?
Read about how to send files with CakePHP. Let me quote the documentation for you:
There are times when you want to send files as responses for your requests. You can accomplish that by using
public function sendFile($id)
{
$file = $this->Attachments->getFile($id);
$this->response->file($file['path']);
// Return response object to prevent controller from trying to render
// a view.
return $this->response;
}
As shown in the above example, you must pass the file path to the method. CakePHP will send a proper content type header if it’s a known file type listed in Cake\Network\Reponse::$_mimeTypes. You can add new types prior to calling Cake\Network\Response::file() by using the Cake\Network\Response::type() method.
If you want, you can also force a file to be downloaded instead of displayed in the browser by specifying the options:
$this->response->file(
$file['path'],
['download' => true, 'name' => 'foo']
);
I am using PHP and I am using the S3 API to upload a file, but I wanted to make sure that this exact filename doesn't already exist in the bucket before upload.
I have found a few examples online that use "file_get_contents" but doesn't this mean that you would have to download the entire file first? Usually, these files are about 10 mb, so ideally, I wouldn't really want to do this.
Is there perhaps a way to use "file_get_contents" without downloading the file?
Or better yet, perhaps I could use an API request to see if the filename exists?
It's not important to me whether or not the content, or filesize, is the same, just the filename.
Gets whether or not the specified Amazon S3 object exists in the specified bucket.
AmazonS3 doesObjectExist
$s3 = new AmazonS3();
$bucket = 'my-bucket' . strtolower($s3->key);
$response = $s3->doesObjectExist($bucket, 'test1.txt');
// Success? (Boolean, not a CFResponse object)
var_dump($response);
try to use code below:
$s3 = new S3();
$info = $s3->getObjectInfo($bucket, $filename);
if ($info)
{
echo 'File exists';
}
else
{
echo 'File does not exists';
}
download the S3 SDK from amazon for php. There is a class called S3; create an object of S3. The object will allow to call the getObjectInfo() method. Pass your S3 bucket name and the file name (often the file name is referred as key). The getObjectInfo() method will return some information if the file exists, otherwise the method will return FALSE.
Please note that the other suggestions are based on version 1 of the AWS SDK for PHP. For version 2, you'll want to be familiar with the latest guide found here:
http://docs.aws.amazon.com/aws-sdk-php/guide/latest/index.html
The "Getting Started" section in the link above will help you get the SDK installed and setup, so be sure to take your time reading through those docs if you haven't done so already. When you're done with the setup, you'll want to be familiar with the stream wrapper method found here:
http://docs.aws.amazon.com/aws-sdk-php/guide/latest/feature-s3-stream-wrapper.html
Finally, below is a brief, real-life example of how you could use it in the flow of your code.
require('vendor/autoload.php');
// your filename
$filename = 'my_file_01.jpg';
// this will use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from env vars
$s3 = Aws\S3\S3Client::factory();
// S3_BUCKET must also be defined in env vars
$bucket = getenv('S3_BUCKET')?: die('No "S3_BUCKET" config var in found in env!');
// register stream wrapper method
$s3->registerStreamWrapper();
// does file exist
$keyExists = file_exists("s3://".$bucket."/".$filename);
if ($keyExists) {
echo 'File exists!';
}
If you have or have the ability to install the PECL extension HTTP then you can use http_head to make a head request easily and check whether the response was 200 or 404.
Updated version for anyone looking for v3 and up...
$s3Client = new \Aws\S3\S3Client([
'version' => 'latest',
'region' => getenv('AWS_REGION'),
'credentials' => [
'key' => getenv('AWS_KEY'),
'secret' => getenv('AWS_SECRET')
]
]);
$response = $s3Client->doesObjectExist(getenv('AWS_S3_BUCKET'),'somefolder/somefile.ext');
if ($response) {
echo "Yay, it exists :)";
} else {
echo "Boo, nothing there :(";
}
Post Moved to: Network timing issues causing PHP to throw "failed to open stream: No such file or directory"
edit: It should be noted that this code was already in place and working for some time. We switch our server configuration from a single mail server with the images stored locally, to a load balanced configuration with a shared NAS box where the images are stored. Then php started to intermittently say the file doesn't exists.
99% of the time when you get an error saying the file doesn't exist, the file doesn't exist, there is a typo or some such.
We have a .Net site which uploads a file to a temporary location. We then send a request to a php application passing in the temporary file. The php app should then move the file from its temporary location to its permanent location.
We know the file exists, because, in .Net, before sending the request to the php application, we are getting a FileInfo object on the file, and checking FileInfo.Exists,
if .Net determines that the file does exist, it sends the filepath as a parameter in a webrequest to the php application.
However, intermittently, about 2 out of 3 times, the php application gives the following error:
"failed to open stream: No such file or directory"
The fact that it is happening intermittently, .Net says it exists, and we can navigate to the location on disk and verify, indicates that yes, the file does actually exists.
So, what are some other possibilites for why php would throw this exception?
.Net:
public void Save(string tempPath, string username, string password, bool deleteSrc, string merakController = "", string fileNamePrefix = "")
{
FileInfo fi = new FileInfo(tempPath);
if (fi.Exists)
{
Name = (fileNamePrefix ?? string.Empty) + fi.Name;
FileSize = fi.Length;
TimeStamp = fi.LastWriteTimeUtc;
string path = fi.FullName;
if (string.IsNullOrEmpty(Type))
throw new Exception("Attachment Type not set");
IceWarpGroupware_Http gwh = new IceWarpGroupware_Http(username, password);
string parameters = string.Format("AttName={0}&AttType={1}&AttDesc={0}&AttSize={2}&AttTime={3}", Name, Type, FileSize, Time);
bool result = gwh.AddAttachment(m_oid, path, parameters, string.Empty, merakController);
if (!result)
throw new Exception("Unable to add attachment \"" + Name + "\"");
try
{
if (deleteSrc)
fi.Delete();
}
catch { }
}
//else
// throw new Exception("Temp file not found");
}
php:
public function AddAttachment($itemID, $src, $parameters, $value)
{
//base64 encode necessary parameters.
$parameters64 = $this->getBase64(urldecode($parameters));
$value64 = $this->getBase64($value);
//Per the API documentation, ADD first, then LOCK, then move manually and then UNLOCK.
$result = $this->FetchComObject()->FunctionCallBase64('AddAttachment', $this->gsid64, $this->getBase64($itemID), $parameters64, $value64); //Add the attachment.
$dest = $this->lockAttachment($this->gsid64, $this->getBase64($itemID), $result); //Lock the attachment and get the destination path.
//This is an enhanced version of the file copy routine for error handling if necessary. Please let alone and commented out when not in use.
// if (!copy($src, $dest))
// {
// if (isset($GLOBALS['php_errormsg']) && !empty($GLOBALS['php_errormsg']))
// throw new RuntimeException($GLOBALS['php_errormsg']);
// throw new RuntimeException("File copy failed with an undefined error. [".$src."]");
// }
$copySuccess = copy($src, $dest); //Comment this line out if using the enhanced file copy above.
//unlink($src);
$success = $this->unlockAttachment($this->gsid64, $this->getBase64($itemID), $result); //Unlock the attachment.
if ($copySuccess == true)
return true;
return false;
}
I have logged in the user. I have retrieved his favourite videos. But when I try to upload videos I get an error
Fatal error File to be uploaded at does not exist or is not readable.
This is the code I use to upload video
$myVideoEntry = new Zend_Gdata_YouTube_VideoEntry();
$file = '/files/trainingvideo1.mp4';
$file = realpath($file);
$filesource = $yt->newMediaFileSource($file);
$filesource->setContentType('video/mp4');
$filesource->setSlug($file);
$myVideoEntry->setMediaSource($filesource);
$myVideoEntry->setVideoTitle('Tutorial 1');
$myVideoEntry->setVideoDescription('Tutorial 1');
$myVideoEntry->setVideoCategory('Entertainment');
$myVideoEntry->SetVideoTags('testme');
$myVideoEntry->setVideoDeveloperTags(array('tester', 'test'));
$uploadUrl = 'http://uploads.gdata.youtube.com/feeds/api/users/default/uploads';
$newEntry = $yt->insertEntry($myVideoEntry, $uploadUrl, 'Zend_Gdata_YouTube_VideoEntry');
I appreciate any help.
Edit: With the information that your realpath() is returning false, we can assume that you're probably configuring zend gdata correctly and just passing in a bad file.
Here is the PHP documentation on realpath(): http://php.net/manual/en/function.realpath.php
The part that matters is:
realpath() returns FALSE on failure, e.g. if the file does not exist.
Note:
The running script must have executable permissions on all directories in the hierarchy, otherwise realpath() will return FALSE.
So at this point I would go ahead and:
Check that the file exists and your URL is correct- perhaps try using an absolute URL at first to test and build up to a relative one progressively
Check permissions on the file, make sure it is executable by all (755 unix permissions, I think)
Good Luck!
Zend Gdata Youtube Doc:
Uploading videos can be done in one of two ways: either by uploading the video directly or by sending just the video meta-data and having a user upload the video through an HTML form.
In order to upload a video directly, you must first construct a new » Zend_Gdata_YouTube_VideoEntry object and specify some required meta-data.
The code below creates a blank » Zend_Gdata_YouTube_VideoEntry to be uploaded. A » Zend_Gdata_App_MediaFileSource object is then used to hold the actual video file. Under the hood, the » Zend_Gdata_YouTube_Extension_MediaGroup object is used to hold all of the video's meta-data. The $uploadUrl is the location where the new entry gets posted to. This can be specified either with the $userName of the currently authenticated user, or, alternatively, you can simply use the string 'default' to refer to the currently authenticated user.
$yt = new Zend_Gdata_YouTube($httpClient);
$myVideoEntry = new Zend_Gdata_YouTube_VideoEntry();
$filesource = $yt->newMediaFileSource('mytestmovie.mov');
$filesource->setContentType('video/quicktime');
$filesource->setSlug('mytestmovie.mov');
$myVideoEntry->setMediaSource($filesource);
$myVideoEntry->setVideoTitle('My Test Movie');
$myVideoEntry->setVideoDescription('My Test Movie');
// Note that category must be a valid YouTube category !
$myVideoEntry->setVideoCategory('Comedy');
// Set keywords, note that this must be a comma separated string
// and that each keyword cannot contain whitespace
$myVideoEntry->SetVideoTags('cars, funny');
// Optionally set some developer tags
$myVideoEntry->setVideoDeveloperTags(array('mydevelopertag',
'anotherdevelopertag'));
// Optionally set the video's location
$yt->registerPackage('Zend_Gdata_Geo');
$yt->registerPackage('Zend_Gdata_Geo_Extension');
$where = $yt->newGeoRssWhere();
$position = $yt->newGmlPos('37.0 -122.0');
$where->point = $yt->newGmlPoint($position);
$myVideoEntry->setWhere($where);
// Upload URI for the currently authenticated user
$uploadUrl =
'http://uploads.gdata.youtube.com/feeds/users/default/uploads';
// Try to upload the video, catching a Zend_Gdata_App_HttpException
// if available or just a regular Zend_Gdata_App_Exception
try {
$newEntry = $yt->insertEntry($myVideoEntry,
$uploadUrl,
'Zend_Gdata_YouTube_VideoEntry');
} catch (Zend_Gdata_App_HttpException $httpException) {
echo $httpException->getRawResponseBody();
} catch (Zend_Gdata_App_Exception $e) {
echo $e->getMessage();
}
To upload a video as private, simply use: $myVideoEntry->setVideoPrivate(); prior to performing the upload. $videoEntry->isVideoPrivate() can be used to check whether a video entry is private or not.
Source: http://framework.zend.com/manual/en/zend.gdata.youtube.html