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;
}
}
}
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);
})});
I am looking for any pointers what I am doing wrong here?
Situation:
I created a simple form on my website that requires the user to enter some text data and an image. This information is then stored on the server - picture separately, and the text data in a json file.
I have tested it with multiple image formats on my desktop (I allow only the most common types, such as jpg, png, or bmp). All seems to be fine. However, it isn't so smooth on mobile (iOS). When I attempt to upload a screenshot (shows as a png format), or a picture I just took (jpg), the response that comes back says Missing picture, which means that no data was received on the server. The thing is that this is not always the case, some screenshots come through, some don't.
I am encoding the picture as a base64 string on the client. I tried logging it to make sure it goes through, and it seems to be fine. However, when I log the received parameters on the server, in these failed cases, the picture string is really empty! All I do is I read the $_REQUEST or $_POST parameters (it's in PHP).
This error has been replicated only on mobile so far. On the front side, I guess this is the most relevant piece of code, but if you need more let me know! You can also inspect that website I included, but it will be slightly more difficult as it's minified.
function init_form_submit () {
var button = document.getElementById('form-submit-btn'),
image_upload_button = document.getElementById('picture');
if (!button || !image_upload_button) return;
image_upload_button.addEventListener('change', function (event) {
preview_image(this);
});
button.addEventListener('click', function (event) {
// Hijack the form submit.
event.preventDefault();
show_form_loader();
var form_validator = FormValidator(GLOB.form_node);
if (!form_validator.valid) {
form_submitted_callback();
}
else {
var http = new XMLHttpRequest();
var formData = new FormData();
formData.append("about", form_validator.fd.about);
formData.append("email", form_validator.fd.email || '');
formData.append("handle", form_validator.fd.handle);
formData.append("name", form_validator.fd.name);
formData.append("picture", GLOB.picture);
http.open('POST', 'https://lmen.us/royalkitten/api/apply-royal-kitten/index.php', true);
http.setRequestHeader('Content-type', 'multipart/form-data');
http.onreadystatechange = function () {
var response;
if (http.readyState !== 4 || http.status !== 200) return;
try {
response = JSON.parse(http.responseText);
}
catch (error) {
response = http.responseText;
console.log(response);
}
form_submitted_callback(response);
}
http.send(formData);
}
});
}
Here is how I store the image data in the GLOB.picture variable. This function is called only twice - once in the code above when the user chooses an image, and once in a callback after a successful submission as a way to reset the form to its original state.
function preview_image (input) {
var preview_label = document.getElementById('picture-label'),
preview_element = document.getElementById('picture-preview');
if (!input.files.length) {
if (preview_label) {
preview_label.innerHTML = 'Select a file';
}
if (preview_element) {
preview_element.src = './images/image-placeholder-600x600.jpg';
}
GLOB.picture = null;
return;
}
var reader = new FileReader(),
file = input.files[0];
if (!file) return;
reader.onload = function (event) {
var image_data = event.target.result;
if (preview_label) {
preview_label.innerHTML = file.name;
}
if (preview_element) {
preview_element.src = image_data;
}
GLOB.picture = image_data;
}
reader.readAsDataURL(file);
}
I guess, the problem is that your image is probably bigger than PHP max size allowed for a POST request. You should send your form as multipart/form-data, and send your image as a file. On the server side, you should get it via $_FILE instead of $_POST...
To send your image as a file, there are multiple solutions. First, you could send a base-64 encoded Blob, but it would be 30% larger than the original file (because of base-64 encoding).
What I would recommend to you is that you send the file in its original binary format, which is easier to implement and faster to upload.
To do so, you just need to send as-is the content of input.files[0]. let's say you set a GLOB.pictureFile=input.files[0] in your preview_image() function. you then just send it in the form like this :
formData.append("picture", GLOB.pictureFile);
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.
I have a page that allows users to upload multiple files and preview them without refreshing the page using jquery. In php I generate a unique file_id for each filename which I would then like to pass back in to JQuery and use it to load up the preview image etc.
I hope I have explained myself clearly.
Thanks for any pointers!
The PHP code:
// php code to upload file and generate unique file id. then...
if (move_uploaded_file($main_image, $file)) {
echo "success";
echo $file_id; // <--- I WANT TO PASS THIS VARIABLE BACK IN TO JQUERY
} else {
echo "error";
}
The J Query Code:
$(function(){
var btnUpload=$('#upload_main');
var mestatus=$('#mestatus');
var button=$('#button');
var files=$('#main_file');
new AjaxUpload(btnUpload, {
action: 'classified-ads/upload-classified-image.php?filenumber=1',
name: 'file1',
onSubmit: function(file, ext){
if (! (ext && /^(jpg|png|jpeg|gif|'')$/.test(ext))){
// extension is not allowed
mestatus.text('Only JPG, PNG or GIF files are allowed');
return false;
}
mestatus.html('<img src="extras/ajaxuploader/progress_bar.gif" height="30" width="340">');
button.html('Loading...');
$('#upload_main').removeClass('hover').addClass('upload_button_loading');
},
onComplete: function(file, response){
//On completion clear the status
mestatus.text('Photo Uploaded Sucessfully!');
button.html('Change Photo');
$('#upload_main').removeClass('upload_button_loading').addClass('upload_button');
//On completion clear the status
files.html('');
//Add uploaded file to list
if(response==="success"){
var file2 = file.replace(/\s/g, "_");
var file_id= file_id;
$('<div></div>').appendTo('#main_file').css('background-image', "url(/ht/classified-ads/temp_images/prev1_<?php echo $parsed_user;?>_"+file_id+")").addClass('main_success');
$("#image1_temp").val("main1_<?php echo $parsed_user;?>_"+file_id+"");
$("#thumbnail_temp").val("thumbnail_<?php echo $parsed_user;?>_"+file_id+"");
} else{
$('<li></li>').appendTo('#main_file').text(file).addClass('error');
}
}
});
});
In your PHP:
$response = array('result' => 'success', 'file_id' => $file_id);
echo json_encode($response);
In your jQuery:
var obj = $.parseJSON(response);
You would then check whether the response was a success with if (obj.result == 'success') and you'd get your file_id with obj.file_id
The simplest way is to do this allowing for MULTIPLE values to be returned:
// Make a variable to hold data to send back and keep track of your separator
$data = '';
$separator = 1;
// Put this in a loop, your loop will depend on how many file uploads you have
// I did not do the loop for you
if (move_uploaded_file($main_image, $file)) {
// echo "success"; Take this out
if ($separater==1){
$data .= $file_id;
} else {
$data .= ','.$file_id;
}
$separater++;
}
// Now outside the loop echo the results back
echo $data;
With this info echoed back you can manipulate it with Javascript (Jquery). Just use something like spli(','); which gives you an array of the file names you needed.
If you only want one value to come back, meaning you only have one file id to send back foregt everything about the loop and the PHP would be this:
if (move_uploaded_file($main_image, $file)) {
// echo "success"; Take this out
$data = $file_id;
// Now echo the results back
// Its been a while since I've done this but there may be times its ok to use return
echo $data;
} else {
// Handel error here
echo "error";
}
Now based off your code this echoed information should be picked up and processed here:
onComplete: function(file, response){ ... }
Instead of looking for "Success" you need to change your code to look for a file id or something like error instead (which is easier) like so:
if(response!=="error"){
// Now you can use your variable "response" here since it contains the file id
} else {
// Handle the error
}
The reason I gave you a long explanation about getting multiple values back is because that is more common as you start making more advanced forms and it wouldn't hurt to use now. This way you can allow multiple file uploads for example. What I do for example when using AJAX is echo back something like this:
1::value,value,value
Now I just split that into arrays first by :: and then by , this line for example says No Error Happened (1 which as we know is also TRUE) and here is your data: value,value,value which you can now use for things in your Jquery or just print to the document.
You should look at the Jquery AJAX page for in depth examples and explanations, it explains the trouble you ran into getting results back. Look at .done .success .complete especially.
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;