Saving XLS from Google Docs with PHP - php

I'm trying to parse XLS files from Google Docs with PHP. It works fine when I manually download a file and then upload it to the server, but when I use PHP to save the exact same XLS file to the server directly, instead of getting all the data in the XLS, the response is:
<b>DOM ELEMENT: </b>HTML<br /><b>ATTRIBUTE: </b>lang => en<br /><b>DOM ELEMENT: </b>HEAD<br /><b>DOM ELEMENT: </b>META<br /><b>ATTRIBUTE: </b>charset => utf-8<br /><b>DOM ELEMENT: </b>META<br /><b>ATTRIBUTE: </b>content => width=300, initial-scale=1<br /><b>ATTRIBUTE: </b>name => viewport<br /><b>DOM ELEMENT: </b>META<br /><b>ATTRIBUTE: </b>name => description<br /><b>ATTRIBUTE: </b>content => Create a new spreadsheet and edit with others at the same time -- from your computer, phone or tablet. Get stuff done with or without an internet connection. Use Sheets to edit Excel files. Free from Google.<br /><b>DOM ELEMENT: </b>TITLE<br />
Here's an example of how I use PHP to save the XLS to the server:
$fileName = 'xls/newday2014.xls';
$xlsURL = 'https://docs.google.com/spreadsheets/d/1KKMiBOlvpKaAJ_MsNfaWGmR6ixL53AjAaLf0R18X3e4/edit#gid=161299136';
file_put_contents($fileName, file_get_contents($xlsURL));

You're missing some fundamental things here with your three liner code:
file_get_contents is not a browser. Any URI (URL) it takes can not have the fragment (in your case #gid=161299136) because this is never send to the server.
The last point also highlights: If you used that exact URI to download with your browser, there is most likely something running in your browser for the download before the correct download URI is created. So you're using the wrong URI to download.
file_get_contents does not log you into google accounts just by magic.
Just making a filename ending with .xls does not change the file-format from HTML magically into an Excel Spreadsheet.
As these are already four fundamental problems with your three lines of code, it should be obvious that the code you're using is unfitable to high degree for what you try to do. I suggest you throw it away and start from scratch doing some research first, e.g. contact the vendor of that webservice for your support options as a PHP developer. Most likely they offer an API for what you're trying to do.
Quickstart: Run a Drive App in PHP (via: How do I read a Google Drive Spreadsheet in PHP?)

Most likely, a cookie is set to your browser, when you log in into Google Docs - this cookie is not present on the file_get_contents($xlsURL) call, so you get different content. The web debugger of your choice will confirm that, so does pasting your URL into a not-logged-in browser.
The cURL extension can hand cookies to the server, but please understand, that this cookie is dynamic - so getting it out of your browser and into cURL is by far not enough. Most likely you will have to walk the complete way from login to the document, including the need to update, whenever Google choses to update.

Related

get filename from google docs using laravel

My site has a feature where users can upload a link to their google docs file. What I want to do is list all the uploaded links in a place. While doing that I need to show the name of the file that is associated with the link.
I can extract the file id from the link and make sure the link is of google docs. Now I need to find a way to get the filename from that. I tried going through the google developer API for google drive, but it is for uploading/doing anything only on the authorized docs. My issue here is, my users upload the files manually to their docs which I have no control over. All I get is a sharable link and somehow get the name out of it. In addition, a thumbnail will also help.
I have tried doing this, but it throws error
$url = "https://www.googleapis.com/drive/v3/files/1G6N6FyXzg7plgEtJn-Cawo5gbghrS8z9_j_cvVqcEDA";
// and
$url = "https://docs.google.com/document/d/1G6N6FyXzg7plgEtJn-Cawo5gbghrS8z9_j_cvVqcEDA/edit?usp=sharing"
$html= file_get_contents($url);
print_r($html);
A dummy link for anyone willing to help: https://docs.google.com/document/d/1G6N6FyXzg7plgEtJn-Cawo5gbghrS8z9_j_cvVqcEDA/edit?usp=sharing
Since we are getting the URL to the file, we can do a couple of things -
get the id to the file
get what type of file is that
Before I explain how to do that, it is better to know that there can be 2 possible situations. One the file is a google docs file, the other google drive file. Those both start with different URLs.
$url = explode('/', Str::after(
Str::after($request->url, 'https://docs.google.com/'), 'https://drive.google.com/'
));
I am using 2 Str::after() to remove the unnecessary part from the URL. Then I am using explode to convert the URL into an array.
Since we have excluded the useless part from the URL, we are left with document/d/1G6N6FyXzg7plgEtJn-Cawo5gbghrS8z9_j_cvVqcEDA/edit?usp=sharing in an array form.
So, if we try to do $url[2], we get the id of the file. Also, "document" is also a good thing to note about. I use those to show proper images. There can be 5 different types of them (4 for google docs and 1 for google drive). Those are - document, spreadsheets, forms, presentation for google docs, and file for google drive. I would recommend everyone store these in the database so that extra calculations are not necessary while displaying it.
Now, to answer the actual part of the question. How to get the name. I have created a new model method to handle that.
public function name()
{
$key = config('app.google_api_key');
$url = "https://www.googleapis.com/drive/v3/files/{$this->file_id}?key={$key}";
$response = Http::get($url)->json();
return $response['name'] ?? 'Private File';
}
Don't forget to add your Google API key in the config file app.php (You need to create one). You can get your API key from Google Developer Console and create a project-specific key. Just to note that this key need not be belonging to the user of the URL.
Also, a thing to note here is that $response returns error code if the file is not set to visible to the public or the file is deleted.

BIRT 4.5 - Disable saving connectstring inside report.rptdesign, PHP to assign connectstring

I am using Birt 4.5 and PHP/MYSQL.
I am able to run birt reports with php. I have enabled tomcat and copied 'birt-runtime-4_5_0/WebViewerExample' to tomcat/webapps and renamed it to birt.
So I can run birt viewer with php;
<?php
$fname = "report/test.rptdesign&__showtitle=false";
$dest = "http://localhost:8081/birt/frameset?__report=";
$dest .= $fname;
header("Location: $dest" );
?>
Above code is working fine. But report connectstring already saved in test.rptdesign file.
I want to remove DB login credentials from test.rptdesign file and assign it while report open with PHP.
I have tried with report parameters. But all the parameters will display on browser address-bar.
Is there any secure way to do this? This is very important when we need to change the database location. It is very hard to change the data source of each and every .rptdesign file.
Thank You,
Supun
I don't believe using report parameters to handle a database connection is the right way. In addition to the address-bar problem you mentionned, it will cause unexpected issues: for example you won't be able to use this database to feed the dataset of another report parameter.
With Tomcat the best approach is to externalize the database connection in a connection pool: easy, robust, and reports might run significantly faster.
Alternatively the datasource can be externalized in a BIRT library (.rptlibrary) and shared across all report-designs: thus only the library needs to be updated when the database location is changing.
I agree with Dominique that sending the database parameters via the query is most likely an inappropriate solution - and you've not given any explanation of whether this is a requirement of the system.
But it is quite trivial to proxy the request via PHP and decorate the URL with the required parameters, something like...
<?php
$_GET['__showtitle']=$_GET['__showtitle'] ? $_GET['__showtitle'] : 'false';
$_GET['__report']=$fname; // NB this should be NULL in your code!
$_GET['dbuser']='a_db_user';
$_GET['passwd']='s3cr3t';
$qry=http_build_query($_GET);
$url="http://localhost:8081/birt/frameset?" . $qry;
// if its simply returning HTML, then just....
$fin=fopen($url, 'r');
while ($l=fgets($fin)) {
print $l;
}
exit;
If the returned content contains relative links the you'll need to rewrite the output stream. If the content type is unusual or you want to project other headers (e.g. for caching) to the browser, then you'll need to use Curl, capture the headers and relay them.

Upload content:// file to server

I have uri of file on android phone : content://com.android.contacts/contacts/472/photo. I got it from PhoneGap Contacts plugin. It is actually contact image. Now I need to upload that image on server but when I upload it and try to see it it is not visible.
I managed to google a little bit and found that for file upload I need to have full file:// path.
Now my question is how to convert content:// to file:// or how to upload files with content:// uri on server?
I have tried using window.resolveLocalFileSystemURI(uri, win, fail); and than
function win(fe){
alert("win");
alert(fe.fullPath);
}
function fail(a){
alert('fail');
}
But somehow it just "skipp" window.resolveLocalFileSystemURI(uri, win, fail);. It is never executed... No error in LogCat and no any alert from these 3 ...
Can this be solution of my problem and why no response is returned?
I don't have direct experience with the contacts plugin, but the docs make me think that you are not looking at a filesystem URI, rather an entry in the contacts database.
[http://docs.phonegap.com/en/3.3.0/cordova_contacts_contacts.md.html#contacts.find]
So, you are likely mis-interpreting the concept of a URI, especially in the context of the filesystem. [http://en.wikipedia.org/wiki/Uniform_resource_identifier] and [http://www.html5rocks.com/en/tutorials/file/filesystem/].
From the plugin docs, we do see that 'photos' is a property of each contact.
how to upload files with content:// uri on server?
for the desired contact, you could create a file using the photos property, and then upload using the phonegap file-transfer plugin. [http://docs.phonegap.com/en/3.3.0/cordova_file_file.md.html#FileTransfer]

debug php code of a facebook app present on heroku

At first apologies in advance if there is some problem in my ques, i am new to heroku ,my basic problem is i have some messed up code, where i want to test if i am able to fetch facebook variables in my own code and use them..
in my .php file i want to put name for person using my facebook app to displayname array variable of array and url of array should get the application users picture..i took the idea to assign these value via the index.php file provided by facebook itself.
My .php file code is :-
$basic = $facebook->api('/me');
$options = array(
'displayName' => he(idx($basic, 'name')),
'image' => array(
'url' => 'https://graph.facebook.com/'.he($id).'/picture?type=square',
'height => '48',
'width => '48'
)
);
but there is something wrong going here which i cant figure out.
i tried to debug it via javascript or other techniques but now able to connect the .php file to some .js file by any means to transfer variable values present in .php file and print them on my browser,i use to edit code at my own system and push it via git and since the code is executed at heroku i cant figure out what errors are creping in..i am using free account as per now so is there any way i can see my code in execution at heroku.. or any help to debug my code efficiently..
Edit1: alternatively is there any way i can pass these variable from my .PHP file to a separate .JS file and print variables in message box or something..any example code given will help a lot..there are many questions asked in this regard to transfer variables from separate .PHP file to separate .JS file..but i found no direct answer for it, all suggest workarounds but no direct way... questions i visited for it are ..
What's the best way to pass a PHP variable to Javascript?
Grab/input php variable in javascript?
and some more but dint find the perfect answer.
Edit2: if my ques needs more info plz let me know,and if second option is the choice left to debug my code ..then can someone give me an example with transferring variable/array present in testfile.php file say present at appfolder/php/lib/testfile.php and output it on browser in HTML format using testjs.js file say present at appfolder/lib/js/testjs.js
A common exchange format between PHP (or other language) and JavaScript is JSON. You can encode an array (or an php object) to json using json_encode, in PHP. Like this :
$options_json = json_encode($options);
So, you can write this javascript variable in your html results, like this :
echo '<script>var options = ', json_encode($options), ';</script>';
Your picture will then be accessible using javascript :
console.log(options);
console.log(options.url);

How do I display protected Amazon S3 images on my secure site using PHP?

I am trying to move images for my site from my host to Amazon S3 cloud hosting. These images are of client work sites and cannot be publicly available. I would like them to be displayed on my site preferably by using the PHP SDK available from Amazon.
So far I have been able to script for the conversion so that I look up records in my database, grab the file path, name it appropriately, and send it to Amazon.
//upload to s3
$s3->create_object($bucket, $folder.$file_name_new, array(
'fileUpload' => $file_temp,
'acl' => AmazonS3::ACL_PRIVATE, //access denied, grantee only own
//'acl' => AmazonS3::ACL_PUBLIC, //image displayed
//'acl' => AmazonS3::ACL_OPEN, //image displayed, grantee everyone has open permission
//'acl' => AmazonS3::ACL_AUTH_READ, //image not displayed, grantee auth users has open permissions
//'acl' => AmazonS3::ACL_OWNER_READ, //image not displayed, grantee only ryan
//'acl' => AmazonS3::ACL_OWNER_FULL_CONTROL, //image not displayed, grantee only ryan
'storage' => AmazonS3::STORAGE_REDUCED
)
);
Before I copy everything over, I have created a simple form to do test upload and display of the image. If I upload an image using ACL_PRIVATE, I can either grab the public url and I will not have access, or I can grab the public url with a temporary key and can display the image.
<?php
//display the image link
$temp_link = $s3->get_object_url($bucket, $folder.$file_name_new, '1 minute');
?>
<a href='<?php echo $temp_link; ?>'><?php echo $temp_link; ?></a><br />
<img src='<?php echo $temp_link; ?>' alt='finding image' /><br />
Using this method, how will my caching work? I'm guessing every time I refresh the page, or modify one of my records, I will be pulling that image again, increasing my get requests.
I have also considered using bucket policies to only allow image retrieval from certain referrers. Do I understand correctly that Amazon is supposed to only fetch requests from pages or domains I specify?
I referenced:
https://forums.aws.amazon.com/thread.jspa?messageID=188183&#188183 to set that up, but then am confused as to which security I need on my objects. It seemed like if I made them Private they still would not display, unless I used the temp link like mentioned previously. If I made them public, I could navigate to them directly, regardless of referrer.
Am I way off what I'm trying to do here? Is this not really supported by S3, or am I missing something simple? I have gone through the SDK documentation and lots of searching and feel like this should be a little more clearly documented so hopefully any input here can help others in this situation. I've read others who name the file with a unique ID, creating security through obscurity, but that won't cut it in my situation, and probably not best practice for anyone trying to be secure.
The best way to serve your images is to generate a url using the PHP SDK. That way the downloads go directly from S3 to your users.
You don't need to download via your servers as #mfonda suggested - you can set any caching headers you like on S3 objects - and if you did you would be losing some major benefits of using S3.
However, as you pointed out in your question, the url will always be changing (actually the querystring) so browsers won't cache the file. The easy work around is simply to always use the same expiry date so that the same querystring is always generated. Or better still 'cache' the url yourself (eg in the database) and reuse it every time.
You'll obviously have to set the expiry time somewhere far into the future, but you can regenerate these urls every so often if you prefer. eg in your database you would store the generated url and the expiry date(you could parse that from the url too). Then either you just use the existing url or, if the expiry date has passed, generate a new one. etc...
You can use bucket policies in your Amazon bucket to allow your application's domain to access the file. In fact, you can even add your local dev domain (ex: mylocaldomain.local) to the access list and you will be able to get your images. Amazon provides sample bucket policies here: http://docs.aws.amazon.com/AmazonS3/latest/dev/AccessPolicyLanguage_UseCases_s3_a.html. This was very helpful to help me serve my images.
The policy below solved the problem that brought me to this SO topic:
{
"Version":"2008-10-17",
"Id":"http referer policy example",
"Statement":[
{
"Sid":"Allow get requests originated from www.example.com and example.com",
"Effect":"Allow",
"Principal":"*",
"Action":"s3:GetObject",
"Resource":"arn:aws:s3:::examplebucket/*",
"Condition":{
"StringLike":{
"aws:Referer":[
"http://www.example.com/*",
"http://example.com/*"
]
}
}
}
]
}
When you talk about security and protecting data from unauthorized users, something is clear: you have to check every time you access that resource that you are entitled to.
That means, that generating an url that can be accessed by anyone (might be difficult to obtain, but still...). The only solution is an image proxy. You can do that with a php script.
There is a fine article from Amazon's blog that sugests using readfile, http://blogs.aws.amazon.com/php/post/Tx2C4WJBMSMW68A/Streaming-Amazon-S3-Objects-From-a-Web-Server
readfile('s3://my-bucket/my-images/php.gif');
You can download the contents from S3 (in a PHP script), then serve them using the correct headers.
As a rough example, say you had the following in image.php:
$s3 = new AmazonS3();
$response = $s3->get_object($bucket, $image_name);
if (!$response->isOK()) {
throw new Exception('Error downloading file from S3');
}
header("Content-Type: image/jpeg");
header("Content-Length: " . strlen($response->body));
die($response->body);
Then in your HTML code, you can do
<img src="image.php">

Categories