Force image caching with javascript - javascript

I am trying to clone an image which is generated randomly.
Although I am using the exact same url a different image is load. (tested in chrome and firefox)
I can't change the image server so I am looking for a pure javascript/jQuery solution.
How do you force the browser to reuse the first image?
Firefox:
Chrome:
Try it yourself (maybe you have to reload it several times to see it)
Code:
http://jsfiddle.net/TRUbK/
$("<img/>").attr('src', img_src)
$("<div/>").css('background', background)
$("#source").clone()
Demo:
http://jsfiddle.net/TRUbK/embedded/result/

You can't change the image server if it isn't yours, but you can trivially write something on your own server to handle it for you.
First write something in your server-side language of choice (PHP, ASP.NET, whatever) that:
Hits http://a.random-image.net/handler.aspx?username=chaosdragon&randomizername=goat&random=292.3402&fromrandomrandomizer=yes and downloads it. You generate a key in one of two way. Either get a hash of the whole thing (MD5 should be fine, it's not a security-related use so worries that it's too weak these days don't apply). Or get the size of the image - the latter could have a few duplicates, but is faster to produce.
If the image isn't already stored, save it in a location using that key as part of its filename, and the content-type as another part (in case there's a mixture of JPEGs and PNGs)
Respond with an XML or JSON response with the URI for the next stage.
In your client side-code, you hit that URI through XmlHttpRequest to obtain the URI to use with your images. If you want a new random one, hit that first URI again, if you want the same image for two or more places, use the same result.
That URI hits something like http://yourserver/storedRandImage?id=XXX where XXX is the key (hash or size as decided above). The handler for that looks up the stored copies of the images, and sends the file down the response stream, with the correct content-type.
This is all really easy technically, but the possible issue is a legal one, since you're storing copies of the images on another server, you may no longer be within the terms of your agreement with the service sending the random images.

You can try saving the base64 representation of the image.
Load the image in an hidden div/canvas, then convert it in base64. (I'm not sure if a canvas can be hidden, nor if it is possible to convery the img using html4 tag)
Now you can store the "stringified" image in a cookie, and use it unlimited times...

The headers being sent from your random image generator script include a Cache-Control: max-age=0 declaration which is in essence telling the browser not to cache the image.
You need to modify your image generator script/server to send proper caching headers if you want the result to be cached.
You also need to make sure that the URL stays the same (I didn't look at that aspect since there were tons of parameter being passed).

There seems to be two workarounds:
If you go with the Canvas method, see if you can get the image to load onto the Canvas itself so that you can manipulate the image data directly instead of making a 2nd http request for the image. You can feed the image data directly onto a 2nd Canvas.
If you're going to build a proxy, you can have the proxy remove the No-Cache directive so that subsequent requests by your browser use the cache (no guarantees here - depends on browser/user settings).

First off, you can "force" anything on the web. If you need to force things, then web development is the wrong medium for you.
What you could try, is to use a canvas element to copy the image. See https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Using_images for examples.

Tell it to stop getting a random image, seems to work the way you want when I add this third replace call:
// Get the canvas element.
var background = ($("#test").css('background-image')),
img_src = background.replace(/^.+\('?"?/, '').replace(/'?"?\).*$/, '').replace(/&fromrandomrandomizer=yes/,'')

try:
var myImg = new Image();
myImg.src = img_src;
and then append "myImg" to where you want:
$(document).append(myImg);

I did this with your fiddler scripts and got the same image every time
#test {
background:url(http://a.random-image.net.nyud.net/handler.aspx?username=chaosdragon&randomizername=goat&random=292.3402&fromrandomrandomizer=yes);
width: 150px;
height: 150px;
}
note the .nyud.net after the domain name.

Related

Is it possible to run a PHP file with HTML on the server

Normally when you have a .PHP file and the client request it, the PHP code is run on the server and the HTML and JavaScript are sent to the client.
Question
Is it possible to have the server request a webpage (local) and run both the PHP code and the HTML with JavaScript on the server? I have created a single .html file that after 3 seconds of processing locally creates the image data for a thumbnail of the given video.
Why
I need to generate a thumbnail for a video. I used shared hosting and my hosting provider doesn't support for ffmpeg. You can, however, generate thumbnails using a canvas and JavaScript. I have already put a lot of pressure on the client. If this is possible, upload and download times would be significantly shorter than using the client.
Attempts
I've tried using file_get_contents(), but it doesn't run the code (Makes sense). Is there a way I could have it open and run for x seconds and then grab the contents?
I've tried using curl to get the file using this function here. I believe it is similar to my previous attempt in that it gets the file contents, but never executes them.
My final attempt was to use new DOMDocument(). I couldn't even get to loading the page though. First, I can't parse it with a video tag. It gives this error:
Warning: DOMDocument::load(): Specification mandates value for attribute controls in
file:\path\to\html\document.html, line: 53 in C:\path\to\php\document.php on line 50
If I were to remove the video tag (which is required), I get errors while parsing my JavaScript. So that attempt also did not work.
Is there a way that I could have PHP process the code (for something on the server) for x seconds before getting the contents? It would allow for time to generate the thumbnail data. If there is another way to do this without using ffmpeg on the server, that would be great.
So as I mentioned in comments, what I'm gonna explain is just an option (not the best one and just answering for your need of running html code!)
Where to do this?
Personally I rather to do this when the video is being uploaded by admin's browser and the best thing is that you can do this as a part of the posting procedure.
So in the page that you want this process to be done, put an invisible iframe like this.
<iframe id="myIframe" style="display: none;"></iframe>
How to begin the process?
I don't know the way you use to upload the videos (and it really is not that important!) but let's assume you want to use formdata. After the video is uploaded you need to know something unique to address the video (let's say an id). So after the video is uploaded, we can recive a code like id:20, initiateThumbnail:true as the result json data. Then we can simply use that hidden iframe to be the browser you've been asking for like this:
$("#myIframe").attr("src","dothething.php?video=20");
Now do what ever you wanted to do in it and change it's content after it's done. Now you need to wait for the result!
$('#myIframe').load(()=>{
let result = $("#myIframe").contents();
// checking result!
});
As you have already thought about, you can handle any errors by processing the result.
Notes
The event listener we used for iframe (iframe.load) fires when you initiate making the thumbnail as well. So be careful with the process of checking result (content of that iframe!)
If you don't use ajax or formdata, simply the action of your form is what I used as iframe.
One question? What happens if network connection goes down during this process? Simple answer! You can check in so many ways that the thumbnail exists or not. If not you can create it once that user requests for it in his browser and upload it back to server and save it for ever (as you did it in admin's panel!)
I think there isn’t another way to generate thumbnail on php server than with ffmpeg.
The only thing you can do, I suppose, is to force canvas generation on page load if you aren’t already doing it.
Anyway you are trying to do something wrong. Php doesn’t evaluate the html code, it’s just a preprocessor and not an interpreter like the browser. You can wait all the time of the world, but you’ll never get the content of the image that only a browser will generate.

Random image upon refresh with only one single image URL

Tried googling for a readily available script, but to no avail. I'm trying to find a script that does the below. Im not sure of there is a name for it.
Thank you in advance!
Function: Banner rotator with a single URL (PHP based)
Example:
User uploads 5 images (468x60px)
The system generates a a single image URL (e.g. http://demo.com/image.gif)
When user goes to the generated URL, it randomly shows 1 of his 5 images
Every time he refreshes the URL, it randomly shows him another one of his images
You can have the server-side code that processes the given URL return a random image each time. If you specify the server-side language (PHP, ASP.Net, JSP, ...) that you are using, I can give an example.
The URL can be something like
http://demo.com/image/
It does not need to have a specific image name in it.
The key is to ensure that the browser does not try and cache that URL. Set appropriate cache headers when returning the image. Again, the mechanics of doing that are specific to your language.
PHP Example
This short tutorial shows you now to select a random image from a folder of images
http://www.heckdesigns.com/tutorials/tutorial-pull-in-a-random-image-from-a-folder-with-php/
URL
You really should not have to require your URL to end in .png or whatever. If you set the Content-Type appropriately (as the tutorial above does), any web browser should display it properly. If that is in fact a requirement, you can use Apache rewrite rules to do that.
See
mod_rewrite and image redirecting

check if an image exists + loading an image without knowing the whole name of it

how can I check if an image exist via javascript.
is it possible to load an image called 145_44.jpg and I only know the first 3 numbers 145?
The html image element has onerror and onload events that will fire if loading the image fails or succeeds respectively.
With regards to loading an image without knowing the correct URI, the answer is no. Its up to the web server to decide what to serve in response to an HTTP request. If the request is for a resource it doesn't know about its very unlikely to serve anything other than a 404 error.
I'm unsure if you'll be able to link to an image without knowing the full name of it, however with the new CSS3 '*" selector you might be able to.
example:
<img src="*145*.jpg" />
this might be able to catch it (i'm at work so i can't test) but give it a shot. the * replaces everything before/after it telling the browser to search for anything with the number 145 in it that is a .jpg

Get an unique identifier in Javascript of an image already loaded by browser

I have some pages that display book informations, and they use an external cover server to get the covers, putting the appropriate url in the src attribute of the img element.
The cover server does not have all the covers, so very often it returns me a default blank cover .
I need a way to know, javascript-side and once the page is loaded, if the cover returned by the cover server is the default blank image, in order to substitute that default blank image with custom html code. So I've tried to calculate an unique identificator for the cover image.
I thought to do this using canvas' drawImage method and then getting an hash of canvas.toDataUrl, but the latter returns me a Security Exception, since the image comes from an external server.
Do you have any better (and working) idea to achieve my goal?
Can't be done at the client side. It would be a security hole (cross-site scripting) if it were possible for script from one domain to look at the contents of an image that came from another domain.
You would have to find the information either using a separate service on the third-party server, or by fetching the image at the server side and comparing it with the filler image. (Suggest using a HEAD request to check the length first and see if that matches the known length of the filler image, for speed.)
Maybe you can do an XmlHttpRequest for the cover image, like a HEAD request, and then look at the ETag header value (or Content-MD5 or something).
Are the width and height of the empty image different to normal images? If so, use that as a guide.

how to clear or replace a cached image

I know there are many ways to prevent image caching (such as via META tags), as well as a few nice tricks to ensure that the current version of an image is shown with every page load (such as image.jpg?x=timestamp), but is there any way to actually clear or replace an image in the browsers cache so that neither of the methods above are necessary?
As an example, lets say there are 100 images on a page and that these images are named "01.jpg", "02.jpg", "03.jpg", etc. If image "42.jpg" is replaced, is there any way to replace it in the cache so that "42.jpg" will automatically display the new image on successive page loads? I can't use the META tag method, because I need everuthing that ISN"T replaced to remain cached, and I can't use the timestamp method, because I don't want ALL of the images to be reloaded every time the page loads.
I've racked my brain and scoured the Internet for a way to do this (preferrably via javascript), but no luck. Any suggestions?
If you're writing the page dynamically, you can add the last-modified timestamp to the URL:
<img src="image.jpg?lastmod=12345678" ...
<meta> is absolutely irrelevant. In fact, you shouldn't try use it for controlling cache at all (by the time anything reads content of the document, it's already cached).
In HTTP each URL is independent. Whatever you do to the HTML document, it won't apply to images.
To control caching you could change URLs each time their content changes. If you update images from time to time, allow them to be cached forever and use a new filename (with a version, hash or a date) for the new image — it's the best solution for long-lived files.
If your image changes very often (every few minutes, or even on each request), then send Cache-control: no-cache or Cache-control: max-age=xx where xx is the number of seconds that image is "fresh".
Random URL for short-lived files is bad idea. It pollutes caches with useless files and forces useful files to be purged sooner.
If you have Apache and mod_headers or mod_expires then create .htaccess file with appropriate rules.
<Files ~ "-nocache\.jpg">
Header set Cache-control "no-cache"
</Files>
Above will make *-nocache.jpg files non-cacheable.
You could also serve images via PHP script (they have awful cachability by default ;)
Contrary to what some of the other answers have said, there IS a way for client-side javascript to replace a cached image. The trick is to create a hidden <iframe>, set its src attribute to the image URL, wait for it to load, then forcibly reload it by calling location.reload(true). That will update the cached copy of the image. You may then replace the <img> elements on your page (or reload your page) to see the updated version of the image.
(Small caveat: if updating individual <img> elements, and if there are more than one having the image that was updated, you've got to clear or remove them ALL, and then replace or reset them. If you do it one-by-one, some browsers will copy the in-memory version of the image from other tags, and the result is you might not see your updated image, despite its being in the cache).
I posted some code to do this kind of update here.
Change the image url like this, add a random string to the querystring.
"image1.jpg?" + DateTime.Now.ToString("ddMMyyyyhhmmsstt");
I'm sure most browsers respect the Last-Modified HTTP header. Send those out and request a new image. It will be cached by the browser if the Last-Modified line doesn't change.
You can append a random number to the image which is like giving it a new version. I have implemented the similar logic and it's working perfectly.
<script>
var num = Math.random();
var imgSrc= "image.png?v="+num;
$(function() {
$('#imgID').attr("src", imgSrc);
})
</script>
I found this article on how to cache bust any file
There are many ways to force a cache bust in this article but this is the way I did it for my image:
fetch('/thing/stuck/in/cache', {method:'POST', credentials:'include'});
The reason the ?x=timestamp trick is used is because that's the only way to do it on a per image basis. That or dynamically generate image names and point to an application that outputs the image.
I suggest you figure out, server side, if the image has been changed/updated, and if so then output your tag with the ?x=timestamp trick to force the new image.
No, there is no way to force a file in a browser cache to be deleted, either by the web server or by anything that you can put into the files it sends. The browser cache is owned by the browser, and controlled by the user.
Hence, you should treat each file and each URL as a precious resource that should be managed carefully.
Therefore, porneL's suggestion of versioning the image files seems to be the best long-term answer. The ETAG is used under normal circumstances, but maybe your efforts have nullified it? Try changing the ETAG, as suggested.
Change the ETAG for the image.
See http://en.wikipedia.org/wiki/URI_scheme
Notice that you can provide a unique username:password# combo as a prefix to the domain portion of the uri. In my experimentation, I've found that inclusion of this with a fake ID (or password I assume) results in the treatment of the resource as unique - thus breaking the caching as you desire.
Simply use a timestamp as the username and as far as I can tell the server ignores this portion of the uri as long as authentication is not turned on.
Btw - I also couldn't use the tricks above with a google map marker icon caching problem I was having where the ?param=timestamp trick worked, but caused issues with disappearing overlays. Never could figure out why this was happening, but so far so good using this method. What I'm unsure of, is if passing fake credentials will have any adverse server performance affects. If anyone knows I'd be interested to know as I'm not yet in high volume production.
Please report back your results.
Since most, if not all, answers and comments here are copies of parts the question, or close enough, I shall throw my 2 cents in.
I just want to point out that even if there is a way it is going to be difficult to implement. The logic of it traps us. From a logical stance telling the browser to replace it's cached images for each changed image on a list since a certain date is ideal BUT... When would you take the list down and how would you know if everyone has the latest version who would visit again?
So my 1st "suggestion", as the OP asked for, is this list theory.
How I see doing this is:
A.) Have a list that our dynamic and manual changed image urls can be stored.
B.) Set a dead date where the catch will be reset and the list will be truncated regardless.
C.0) Check list on site entrance vs browser via i frame which could be ran in the background with a shorter cache header set to re-cache them all against the farthest date on the list or something of that nature.
C.1) Using the Iframe or ajax/xhr request I'm thinking you could loop through each image of the list refreshing the page to show a different image and check the cache against it's own modified date. So on this image's onload use serverside to decipher if it is not the last image when it is loaded go to the next image.
C.1a) This would mean that our list may need more information per image and I think the obvious one is the possible need of some server side script to adjust the headers as required by each image to minimize the footstep of re-caching changed site images.
My 2nd "suggestion" would be to notify the user of changes and direct them to clear their cache. (Carefully, remove only images and files when possible or warn them of data removal due to the process)
P.S. This is just an educated ideation. A quick theory. If/when I make it I will post the final. Probably not here because it will require server side scripting. This is at least a suggestion not mentioned in the OP's question that he say's he already tried.
It sounds like the base of your question is how to get the old version of the image out of the cache. I've had success just making a new call and specifying in the header not to pull from cache. You're just throwing this away once you fetch it, but the browser's cache should have the updated image at that point.
var headers = new Headers()
headers.append('pragma', 'no-cache')
headers.append('cache-control', 'no-cache')
var init = {
method: 'GET',
headers: headers,
mode: 'no-cors',
cache: 'no-cache',
}
fetch(new Request('path/to.file'), init)
However, it's important to recognize that this only affects the browser this is called from. If you want a new version of the file for any browser once the image is replaced, that will need to be accomplished via server configuration.
Here is a solution using the PHP function filemtime():
<?php
$addthis = filemtime('myimf.jpg');
?>
<img src="myimg.jpg?"<?= $addthis;?> >
Use the file modified time as a parameter will cause it to read from a cached version until the file has changed. This approach is better than using e.g. a random number as caching will still work if the file has not changed.
In the event that an image is re-uploaded, is there a way to CLEAR or REPLACE the previously cached image client-side? In my example above, the goal is to make the browser forget what "42.jpg" is
You're running firefox right?
Find the Tools Menu
Select Clear Private Data
Untick all the checkboxes except make sure Cache is Checked
Press OK
:-)
In all seriousness, I've never heard of such a thing existing, and I doubt there is an API for it. I can't imagine it'd be a good idea on part of browser developers to let you go poking around in their cache, and there's no motivation that I can see for them to ever implement such a feature.
I CANNOT use the META tag method OR the timestamp method, because I want all of the images cached under normal circumstances.
Why can't you use a timestamp (or etag, which amounts to the same thing)? Remember you should be using the timestamp of the image file itself, not just Time.Now.
I hate to be the bearer of bad news, but you don't have any other options.
If the images don't change, neither will the timestamp, so everything will be cached "under normal circumstances". If the images do change, they'll get a new timestamp (which they'll need to for caching reasons), but then that timestamp will remain valid forever until someone replaces the image again.
When changing the image filename is not an option then use a server side session variable and a javascript window.location.reload() function. As follows:
After Upload Complete:
Session("reload") = "yes"
On page_load:
If Session("reload") = "yes" Then
Session("reload") = Nothing
ClientScript.RegisterStartupScript(Me.GetType), "ReloadImages", "window.location.reload();", True)
End If
This allows the client browser to refresh only once because the session variable is reset after one occurance.
Hope this helps.
To replace cache for pictore you can store on server-side some version value and when you load picture just send this value instead timestamp. When your image will be changed change it`s version.
Try this code snippet:
var url = imgUrl? + Math.random();
This will make sure that each request is unique, so you will get the latest image always.
After much testing, the solution I have found in the following way.
1- I create a temporary folder to copy the images with the name adding time () .. (if the folder exists I delete content)
2- load the images from that temporary local folder
in this way I always make sure that the browser never caches images and works 100% correctly.
if (!is_dir(getcwd(). 'articulostemp')){
$oldmask = umask(0);mkdir(getcwd(). 'articulostemp', 0775);umask($oldmask);
}else{
rrmfiles(getcwd(). 'articulostemp');
}
foreach ($images as $image) {
$tmpname = time().'-'.$image;
$srcimage = getcwd().'articulos/'.$image;
$tmpimage = getcwd().'articulostemp/'.$tmpname;
copy($srcimage,$tmpimage);
$urlimage='articulostemp/'.$tmpname;
echo ' <img loading="lazy" src="'.$urlimage.'"/> ';
}
try below solutions,
myImg.src = "http://localhost/image.jpg?" + new Date().getTime();
Above solutions work for me :)
I usually do the same as #Greg told us, and I have a function for that:
function addMagicRefresh(url)
{
var symbol = url.indexOf('?') == -1 ? '?' : '&';
var magic = Math.random()*999999;
return url + symbol + 'magic=' + magic;
}
This will work since your server accepts it and you don't use the "magic" parameter any other way.
I hope it helps.
I have tried something ridiculously simple:
Go to FTP folder of the website and rename the IMG folder to IMG2. Refresh your website and you will see the images will be missing. Then rename the folder IMG2 back to IMG and it's done, at least it worked for me in Safari.

Categories