I am trying to render an image using php for my website that will dynamically display images straight from the Google Places API (Reference https://developers.google.com/places/web-service/photos?hl=en)
The image source looks like the following example:
https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=CnRtAAAATLZNl354RwP_9UKbQ_5Psy40texXePv4oAlgP4qNEkdIrkyse7rPXYGd9D_Uj1rVsQdWT4oRz4QrYAJNpFX7rzqqMlZw2h2E2y5IKMUZ7ouD_SlcHxYq1yL4KbKUv3qtWgTK0A6QbGh87GB3sscrHRIQiG2RrmU_jF4tENr9wGS_YxoUSSDrYjWmrNfeEHSGSc3FyhNLlBU&key=API_KEY
If you visit this URL via your browser it will render an image and this is no longer the URL you see.
My issue is that when viewing the page source, this is exactly the image source URL you see which is bad because my key is then publicized. What is the proper way to render images while keeping my key private? I have searched the API and the web for this but to no avail. I did see some tricks using file_get_contents and file_put_contents but my web host does not allow that. Finally, saving the images is against the api rules so that is not an option.
Any tips would be appreciated. Thanks in advance.
You may send a HEAD-request to the particular URL and extract the content of the Location-header:
<?php
$context = stream_context_create(array('http' =>array('method'=>'HEAD')));
$fp = fopen('desiredPlacesApiImgUrl', 'rb', false, $context);
$meta = stream_get_meta_data($fp);
if(isset($meta['wrapper_data'])){
$location=preg_grep('#^\s*Location:#',$meta['wrapper_data']);
if(count($location)){
$imgUrl=trim(preg_replace('#^Location:#i','',reset($location)));
die($imgUrl);//the desired img-url
}
}
fclose($fp);
?>
But when file_get_contents isn't allowed on your server I'm afraid fopen also isn't allowed for external URLs.
Another option: use the Maps-Javascript-API, request the place and the response should contain the desired URL (without using any key).
Demo:
function loadPlacePhotos() {
var photos = document.querySelectorAll('img[data-place]'),
service = new google.maps.places
.PlacesService(document.createElement('div'));
for (var i = 0; i < photos.length; ++i) {
(function(photo) {
service.getDetails({
placeId: photo.getAttribute('data-place')
}, function(r) {
if (r.photos.length) {
google.maps.event.addDomListener(photo, 'click', function() {
photo.setAttribute('src', r.photos[0].getUrl({
maxHeight: 100
}));
photo.style.visibility = 'visible';
if (r.photos.length > 1) {
r.photos.push(r.photos.shift());
photo.setAttribute('title', 'click to see next photo');
photo.style.cursor = 'pointer';
} else {
google.maps.event.clearListeners(photo, 'click');
}
});
google.maps.event.trigger(photo, 'click');
}
});
}(photos[i]));
}
}
body::before {
content: url(https://maps.gstatic.com/mapfiles/api-3/images/powered-by-google-on-white2.png);
}
img[data-place] {
visibility: hidden;
display: block;
}
<ul>
<li>
Google: Mountain View
<img data-place="ChIJj61dQgK6j4AR4GeTYWZsKWw" />
</li>
<li>
Google: Sydney
<img data-place="ChIJN1t_tDeuEmsRUsoyG83frY4" />
</li>
<li>
Google: Berlin
<img data-place="ChIJReW1rcRRqEcRaY3CuKBdqZE" />
</li>
</ul>
<script defer src="https://maps.googleapis.com/maps/api/js?v=3&libraries=places&callback=loadPlacePhotos"></script>
The demo uses a custom attribute for images data-place which will be assigned to a placeId of a particular place. It parses these images, requests the photos and displays them(when there ar more than 1 photo the user can switch between the photos by clicking on the image )
However, it must not be a problem when your key is visible, set the allowed referers for your (browser)-key and you can use the key without a risk on your own domain.
Related
I am building a testing website. In login confirmation, I have to show the examinee their pictures, which is already saved in Google Drive Folder.
$optParams = array(
'pageSize' => 1,
'fields' => 'nextPageToken, files(contentHints/thumbnail,fileExtension,id,name,size)',
'q' =>"mimeType contains 'image/' AND name contains '".$imageId."' AND '".$folderIdId."' in parents"
);
$results = $googleDriveService->files->listFiles($optParams);
if (count($results->getFiles()) == 0) {
print "No files found.\n";
} else {
print "Files:\n";
foreach ($results->getFiles() as $file) {
printf("%s (%s)\n", $file->getName(), $file->getId());
}
}
This is what I used to get the file ID. Now in order to preview the image to the page, do I have to download the image (then delete it later) in order to show it, or is there another way to do it without downloading?
Answer:
While Drive is not designed to be a hosting platform, you use the preview link as a workaround.
More Information:
I really should reiterate here: Drive is not designed to be an image hosting platform. It is a file sharing and cloud storage solution primarily, but does provide methods of viewing images via preview, view and embed links.
You can use the following link, replacing [ID] with your image ID to embed or preview an image in a page:
https://drive.google.com/uc?export=view&id=[ID]
NB: While this works, the image will load slowly as image hosting is not the M.O. of Drive.
There is also an iframe option provided in the form of an embed:
<iframe src="https://drive.google.com/file/d/[ID]/preview" width="640" height="480"></iframe>
This iframe embed is obtainable from the Drive UI:
After double-clicking your image at drive.google.com, and following the ⋮ > Open in new window menu item, in the newly opened tab follow the ⋮ > Embed item... menu option and the iframe code will open in a modal.
This works for me. You need to follow the GOOGLE DRIVE API docs. This code takes a file and uploads it to google drive. Records the URL and the "name" in a database for use in displaying the images later. I installed multer in express.js to help with multiple image uploads.
app.post('/api/uploadmultiple', uploader.any("files", 12),
async (req, res, next) => {
const scopes = [
'https://www.googleapis.com/auth/drive'
];
const stream = require('stream');
const { google } = require('googleapis');
const credentials = require('./google-credentials.json');
let fileObject = req.files[0];
let bufferStream = new stream.PassThrough();
bufferStream.end(fileObject.buffer);
const auth = new google.auth.JWT(
credentials.client_email, null,
credentials.private_key, scopes
);
const drive = google.drive({ version: "v3", auth });
const fileName = req.files[0].originalname;
const fileType = req.files[0].mimetype;
var fileMetadata = {
name: fileName, // file name that will be saved in google drive
};
var media = {
mimeType: fileType,
body: req.files[0].buffer, // Reading the file from our server
};
var petname = req.body.petname;
// Uploading Single image to drive
drive.files.create(
{
media: {
mimeType: fileType,
body: bufferStream
},
resource: {
name: fileName,
// if you want to store the file in the root, remove this parents
parents: ['GET THIS ID FROM GOOGLE DRIVE']
},
fields: 'id',
}).then(function (resp) {
if (resp.data) {
res.status(200).end("File uploaded");
var fileLocation = "https://drive.google.com/uc?id=" + resp.data.id;
console.log("Upload Success", fileLocation);
db.addPet(petname, fileLocation);
db.addImage(petname, fileName, fileLocation);
}
console.log(resp.data.id,'resp');
}).catch(function (error) {
console.log(error);
res.status(500);
})});
now im doing AXIOS code combine with laravel to get image from instagram URL. the URL is this https://www.instagram.com/p/B_zZCRpB895/media/?size=t
AXIOS is new from me. to get the image, i tried this simple code. i set this code into my frontend site
<img id="imgsrc" src="" >
<script>
axios
.get('https://www.instagram.com/p/B_zZCRpB895/media/?size=t', {
responseType: 'arraybuffer'
})
.then(response => {
const buffer = Buffer.from(response.data, 'base64');
document.getElementById("imgsrc").src = Buffer;
console.log(Buffer);
})
.catch(ex => {
console.error(ex);
});
</script>
but the image not display into <img id="imgsrc" src="" >
i really want that, when we open the page. the instagram image can display.
how to solve this matter. please help.
you can use file reader to get base64 and set it as the image source :
<script>
axios.get('https://www.instagram.com/p/B_zZCRpB895/media/?size=t', {responseType: "blob"})
.then(function (response) {
var reader = new window.FileReader();
reader.readAsDataURL(response.data);
reader.onload = function () {
document.getElementById("imgsrc").src = reader.result;
}
});
</script>
Is there a particular reason you are retrieving this via an AJAX call using axios?
The endpoint you provided returns an image source already. To make it appear in the image element all you need to do is set the src to the endpoint URL as shown below. Unless you need to run a process to do something to the image you don't need to get the data as an array buffer.
document.getElementById("imgsrc").src = "https://www.instagram.com/p/B_zZCRpB895/media/?size=t";
I'm attempting to write a small image proxier script on my website, because imgur is blocked on my current network and want to be able to see images from Stack Overflow.
I've got this code on my personal website:
$image = $_GET['url'];
$imageData = base64_encode(file_get_contents($image));
echo '<img src="data:image/jpeg;base64,'.$imageData.'">';
This should take the URL of an image, have my server download the image and then display it (by itself) on the page.
This works, for example, if I was trying to proxy my Stack Overflow account profile picture, I could use this link, which, as you can see works totally fine to display the picture on the page. I can see this image even on my blocked network.
Now, I've created a userscript that automatically transverses all images and links on a loaded page, and switches it's source/href link with a proxied version.
This is the part that is not working for me, when supplied with a proxied link, the image does not show in the element.
Here is my userscript:
function runProxier() {
$('img').each(function() {
var image = $(this);
if(!image.data('image_proxier_converted')) {
image.attr('src', getProxyLink(image.attr('src')));
image.attr('data-image_proxier_converted', 1);
}
});
$('a').each(function() {
var link = $(this);
if(!link.data('image_proxier_converted')) {
link.attr('href', getProxyLink(link.attr('href')));
link.attr('data-image_proxier_converted', 1);
}
});
}
function getProxyLink(givenLink) {
if (givenLink) {
if (replace_from.some(function(v) {
return givenLink.indexOf(v) >= 0;
})) {
return proxy_link + encodeURI(givenLink);
} else {
return givenLink;
}
}
}
When ran on my example, my profile picture, the link is properly converted.
<img src="//grumpycrouton.com/other/image_proxy/?url=https://i.stack.imgur.com/YkRwP.png?s=48&g=1" alt="" width="24" height="24" class="-avatar js-avatar-me" data-image_proxier_converted="1">
But the image does not show, it's still blank in my menu bar.
Why is my image not displayed?
I was able to resolve this problem by using this code on my server:
<?php
if(!isset($_GET['url'])) {
die('No image given');
}
header('Content-Type: image/jpeg');
readfile($_GET['url']);
?>
The header() call tells the client that it should serve an image, and readfile() will download (but not store on my server) and display the image.
I also noticed my URL was not properly encoding to be sent to the server, so I altered my userscript like so:
function getProxyLink(givenLink) {
if (givenLink) {
if (replace_from.some(function(v) {
return givenLink.indexOf(v) >= 0;
})) {
var new_link = proxy_link + encodeURIComponent(givenLink);
console.log(new_link);
return new_link;
} else {
return givenLink;
}
}
}
I am using a PHP script to read some folders in directory and based on their names retrieve their posters. All of this works fine on localhost. However, when opening externally, this does not work and results in blank images.
A screenshot from localhost:
The problem can be found at 89.241.171.100/Prac/.
PHP generating img tag:
while (false !== ($entry = readdir($handle))) {
$counter++;
echo "<span class='title'>
<img src='holder.js/200x280/text:$entry'
alt='$entry'
onload='loader(this, \"$entry\")' />
</span>";
if($counter == 5) break;
}
PHP fetching the src for the images called via ajax from loader():
if($_POST['title']) {
$title = $_POST['title'];
$imdb = new Imdb();
$movieArray = $imdb->getMovieInfo("$title");
$link = $movieArray["poster_large"];
echo $link;
}
Loader() function:
$.ajax({
type: 'post',
url: 'loader.php',
data: 'title='+title,
success: function(data) {
img.src = data;
}
});
This looks like an issue with the way you're loading it. These images are being provided via Akamai's CDN and it's not liking the referrer that it's getting.
Here's what's being returned instead of the image payload.
<HTML><HEAD>
<TITLE>Referral Denied</TITLE>
</HEAD><BODY>
<H1>Referral Denied</H1>
You don't have permission to access "http://ia.media-imdb.com/images/M/MV5BMTM5NjM0ODY1NF5BMl5BanBnXkFtZTcwMjk5NjI0Ng##._V1._SY500.jpg" on this server.<P>
Reference #24.24c633b8.1366714063.2a353f15
</BODY></HTML>
I'm not encouraging breaching anyone's terms but this might be of some use to you, I suspect that passing an empty referrer will fix the problem as when you visit the image URL directly it works (and doesn't send a referrer).
EDIT:
This fiddle is a working example of what I was suggesting earlier. You'll notice the image directly linked is dead, but the one with no referrer loads perfectly.
U could use the Imdb API
Just request the data with : http://imdbapi.org/?id={id}&type=json&plot=simple&episode=1&lang=en-US&aka=simple&release=simple
{id} being the imdb id of the movie. Then u can access the picture with :
$data = json_decode(file_get_contents("http://imdbapi.org/?id={id}&type=json&plot=simple&episode=1&lang=en-US&aka=simple&release=simple"));
$img = $data->poster;
I'm still learning both PHP and jQuery, and this seems to me to be a reasonably complex thing to try and do.
What I'd like to be able to do is use jCarousel's textscroller capability to display a list of URLs generated by a PHP function rather than the XML feed and URLs that jCarousel is written for. (Demo: http://sorgalla.com/projects/jcarousel/examples/special_textscroller.html)
The WordPress PHP function I want to use generates a list of URLs with some html markup for some or all posts in a WordPress category.
As a result, I think I don't need jCarousel's XML function or the html creator function, and I don't need to truncate strings.
So, is it possible to include the PHP function in the jQuery function, or would I have the jQuery function retrieve the URL list from the PHP function, something similar to providing a XML feed to jCarousel? Do I need to use the jQuery-PHP library? http://jquery.hohli.com
Any answers will be appreciated. - Mark
This are the jCarousel functions that use the XML feed: (I omitted document ready function)
function mycarousel_initCallback(carousel, state)
{
carousel.lock();
jQuery.get(
'special_textscroller.php',
{
'feed': 'http://jquery.com/blog/feed/atom/'
},
function(xml) {
mycarousel_itemAddCallback(carousel, xml);
},
'xml'
);
};
function mycarousel_itemAddCallback(carousel, xml)
{
var $items = jQuery('item', xml);
$items.each(function(i) {
carousel.add(i + 1, mycarousel_getItemHTML(this));
});
carousel.size($items.size());
// Unlock and setup.
carousel.unlock();
carousel.setup();
};
/**
* Item html creation helper.
*/
function mycarousel_getItemHTML(item)
{
return '<h3>'+$('title', item).text()+'</h3><p>'+mycarousel_truncate($('description', item).text(), 90)+'</p>';
};
/**
* Utility function for truncating a string without breaking words.
*/
function mycarousel_truncate(str, length, suffix) {
if (str.length <= length) {
return str;
}
if (suffix == undefined) {
suffix = '...';
}
return str.substr(0, length).replace(/\s+?(\S+)?$/g, '') + suffix;
};
And this WordPress PHP function:
<?php $my_query = new WP_Query('category_name=mycategory&showposts=10'); ?><?php while ($my_query->have_posts()) : $my_query->the_post(); ?><?php the_title(); ?><br /><br /><?php endwhile; ?>
generates html like this:
link title<br /><br />link title<br /><br />, etc....
which is the html I'd like the jCarousel text scroller to display.
you seem to be missing the actual call to start the carousel
the html needs to be wrapped in a div
<div id="mycarousel">
link title<br /><br />
link title<br /><br />, etc....
</div>
then call
jQuery('#mycarousel').jcarousel({
vertical: true,
size: 0,
initCallback: mycarousel_initCallback
});
in
function mycarousel_initCallback(carousel, state){
carousel.lock();
jQuery.get(
'special_textscroller.php',
{
'feed': 'http://jquery.com/blog/feed/atom/'
},
function(xml) {
mycarousel_itemAddCallback(carousel, xml);
},
'xml'
);};
this method you need to put your WP-php file name in place of "special_textscroller.php"
file or can change the "special_textscroller.php" with your WP function .
Again , you need to send output via XML format only if you do not want to change other "jCarousel" functions.