I have found weird bug in my application. I am using VueJS3 and typescript. I am creating a media gallery, where users can manage assets. All endpoints and backend side of application works perfectly. Currently i am working on updating image files(updating image field). My code works in theory, image url updates to a new one, but even the url is newer, image that is rendered is old image(before update). When i try to view my application in incognito window, my newer image is showing. But it does not work otherwise(works if and only user clears his cache) I hope i explained myself clearly, it is a little complicated :)
When i fetch the data from api, they don't have any src, so i have to create a property when using the data. Here is the code below.
const { res, err } = await this.$api.image.getAll(params)
res.data.items.forEach(async (image: Image<Populated>) => {
image.src = this.$fileHandler(image._id)
})
Note: File handler is a special method that gives the image source by id
Apparently your assets get cached, and there are multiple ways to solve that.
Not diving too much into caching strategies and cache control tags, just do
image.src = `${this.$fileHandler(image._id)}?_=${+new Date()}`
This will generate a unique (almost) URL for your image, invalidating every previous cached one.
As documented, TinyMCE allows uploading images automatically: one defines an endpoint (images_upload_url), which is expected to upload the image and return the location for TinyMCE to use in markup.
However, when pasting, dragging or inserting an image from a URL — for example, https://somecdn.com/image.png — TinyMCE will simply embed the image tag with the somecdn.com source, instead of sending the URL to images_upload_url to be uploaded.
I've scoured through the docs here and haven't found any way to configure TinyMCE to do this. Is there a method I can override in order to upload images from URLs as well as local image uploads?
Summary
To clarify:
Current behavior with local image dragged in: TinyMCE sends the image to the URL specified in images_upload_url, then embeds the source returned.
Current behavior with remote image dragged in: TinyMCE embeds the remote image, sourced with its remote URL.
Desired behavior with remote image dragged in, similar to well established products like Microsoft's GroupMe: TinyMCE sends the image URL to the URL specified in images_upload_url, then embeds the source returned. I can figure out how to upload the URL & manually embed the image in TinyMCE, but I need to know what event to intercept to get the dragged-in image URL!
With some tinkering, I was able to figure out how to handle remote images in TinyMCE!
As I'm using TinyMCE with React, I added an onDrop event:
<Editor
onDrop={onDrop}
And here is my method implementation, with comments:
const onDrop = useCallback((e) => {
const image_url = e.dataTransfer.getData("URL");
/*
If this is a local file, use the default functionality
provided using images_upload_url
*/
if (!image_url) {
return;
}
/*
Otherwise, intercept the drop event, get the file URL,
send it to the API to be uploaded, then embed in content
*/
e.preventDefault();
filesAPI
.upload({
image_url,
})
.then((response) => {
const { location } = response.data;
editorRef.current.execCommand(
"mceInsertContent",
false,
`<img src='${location}' />`
);
});
return false;
}, []);
The implementation seems to work pretty well! When local images are dropped in, they're processed by the default handler; otherwise the onDrop method uploads the images & inserts a tag with their location. Note that filesAPI in this context is just my app's wrapper around an axios fetch call.
What you are wanting to do is not technically possible for a great many "remote" images as most sites won't have the appropriate CORS headers in place to allow for what you want to happen. You can fetch/proxy the image via some server side code and then do whatever you want with it once it is fetched server side.
All that being said you also enter a slippery slope of "taking" someone else's intellectual property and storing/serving it from your server which in many cases would be against copyright laws.
EDIT (based on your comments):
The images_upload_url feature is not designed to do what you want it to do. It is not that you cannot do what you are describing but images_upload_url won't do that for you. You can try to use some of TinyMCE's events to capture content insertion and trigger that sort of behavior or you could simply wait for the content to be saved to the server and perform that processing when the content is prepared for saving to your data store.
There are a whole host of events that TinyMCE provides along with some of the standard browser events:
https://www.tiny.cloud/docs/advanced/events/#handlingeditorevents
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.
I am building a Discussion Forum as part of a bigger application I am building, the forum is just 1 section of the Application.
For my TextArea fields when posting a new Topic or a Post Reply, I have decided that nothing is as good as the PageDown Markdown Library. It is the same one that StackOverflow uses on all their sites and it works better than many of it's competitors.
The way the library ships though, I am not happy with the default Insert Image functionality. You hit the button to insert an image and it allows you to enter a URL for an Image and then it inserts the proper MarkDown syntax to show the linked image.
This just won't cut it. I need the functionality that you see on StackOverflow! Very similar anyways.
I need it to show a Dialog when you click the Insert Image button, like it does now, but instead of just an input field for a Image URL, it will have 2 filed options...
Upload image from your computer
Insert an Image URL and it will then DOWNLOAD the image from that URL and insert it into the post just as if you had uploaded it from your computer. This is important to not confuse this step. IT should not simply insert the Image linking it to the original Image URL. Instead it will take that URL and download/upload the Image to the same server that the upload from computer option does and then it will insert the NEW Image URL pointing to the newly uploaded image!
Based on some simple HTML like below for a Dialog window with a filed for my Upload from Computer functionality, which I already have working. I need to come up with some JavaScript and PHP that will download/save a remote image to my upload folder on my server when a button is clicked using only the URL that will be inside the URL text input field.
So it will need to do a few things...
Fetch and save an image file to my uploads folder using PHP when the only thing that the PHP function will receive is a URL of the image which could be on the same server or most likely a remote server.
After successfully saving/uploading an image from the URL, the PHP function will return a JSON string with the status/error and if successful then it will also return the actual URL and filename of where the new image is saved on the local server. The JavaScript/AJAX script will receive this JSON response and insert the Markdown syntax for the image into the PageDown editor.
The PHP function will need to ensure that the URL that it is trying to save/download is a valid image file and not some malicious file! Also not simply just some file of the wrong filetype like a non-image file unless we are allowing the file type.
It will be part of a module installed on many dinosaur servers so it needs to work on as many servers as possible too!
From the web
From your computer
I would be greatful of any help, tips, code snippets or anything to help with this. At this stage I really just need to build a nie PHP function that will upload images from a remote URL and also ensure that the URL passed in is a real image file or even better that it is in the allowed file types array!
A couple years ago I had started this but have now lost it and I am starting over and don't remeber much about how I went about doing it then.
The easiest way to download a file from a remote server would be to use copy (http://php.net/manual/en/function.copy.php):
copy('http://someurl.com/image.png', '/var/www/uploads/image.png');
As this function returns a bool, it is easy to determine whether the operation was successful and create a JSON response.
To verify that the file is an actual image, there is unfortunately no way that is 100% sure. It is probably enough to check the mimetype though. You can use finfo for that (http://php.net/manual/en/function.finfo-file.php):
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, $filename);
finfo_close($finfo);
For a gif, this would return image/gif for example. You will have to hardcode a list of all mimetypes you want to allow.