PHP Grabbing images without token in URL

When opening the image in a new tabs or viewing the source code of the page the images will show the token at the end of the URL parameter. My code below is meant to be that way, but only because I have not figured out a way to do otherwise. Can anyone help with a way to grab images from the XML and not show the token? You can put your server info in the top 2 lines of the code below and you’ll see what I mean.

<?php
$host = '127.0.0.1';
$token = "xxxxxxxxxx";
$movies = '1';
$url = "https://$host/library/sections/$movies/recentlyAdded?X-Plex-Token=$token";
$xml = simplexml_load_file($url);
$imgurl = "https://$host/photo/:/transcode?url=";
$imgsize = "&width=328&height=500&X-Plex-Token=$token";

foreach($xml as $child) {
	$image = $child['thumb'];
		echo '<img src="'.$imgurl.$image.$imgsize.'">';
}
?>

Not a PHP dude, but you can add the token to the header instead

Ref: https://github.com/Dachande663/Plex-Export/blob/master/cli.php#L53

Edit: but looks more like you want to provide an http page with download links, and if so, instead of an active site downloading for you, you can’t

1 Like

For me, the best way to do that is to download the image in advance (cache it somewhere) then display it.

I refactored your code but this is not the best way, I just want to show you how it works on the fly. I suggest to cache it somewhere to prevent performance issue.

<?php
$host = '127.0.0.1';
$token = "xxxxxxxxxx";
$movies = '1';
$url = "https://$host/library/sections/$movies/recentlyAdded?X-Plex-Token=$token";
$xml = simplexml_load_file($url);
$imgurl = "https://$host/photo/:/transcode?url=";
$imgsize = "&width=328&height=500&X-Plex-Token=$token";

foreach($xml as $child) {
	$image = $child['thumb'];
    $img_url = $imgurl.$image.$imgsize;
    // use file_get_contents to download the image or any other function that can download the file from url.
    $img_encoded = base64_encode(file_get_contents($img_url));
    $img_src = 'data:;base64,'.$img_encoded;
		echo '<img src="'.$img_src.'">';
}
?>
1 Like

Thank you, I will take a look and see if I can come up with anything on that.

Just tried this method and it loads extremely slow. Like 10 times slower than without the base64 encoding. How are you caching yours?

Thank you

You have lots of options, you can use redis to save the base64 encoded image (serialized) and assign to specific key, if the key exist already then skip file_get_contents (downloading) and use the cache instead. That’s just one of the example, you can also use your filesystem as storage. there’s hundreds of ways to do that. If you use your file system as storage, no need for base64 encoding. Just like what I have said, I just show you an example how to do it in the backend. you just need to optimize it.

the process is like

  1. download -> cache -> display (will be slow at first time)
  2. cache -> display (will be lightning fast)

Plex implementation (token when embedding or getting image) for me is just right, for security reason it should have token. External developers just need to find another way how to display the image without exposing the token, the way is, download the image in the backend and cache it somewhere.

If I will be the developer, I will use varnish-cache.

how:

  1. create another service/route for plex images (php or any other language of your choice)

  2. cache all the routes from image.php using varnish (lots of tutorial in the internet how to create vcl)

  3. embed the service/route in your client/front-end

    • Ex) <img src="https://mydomain.tld/images.php?thumb=1601481139&width=328&height=500" />

So I think I got this working in a simple way. Can anyone give any tips on the following code. Everything seems to be working correctly. I currently have the cache refreshing every month.

I still need to figure something out. The way it is working now is it will just refresh the images that is finds according to the XML (last 100). How can I have it delete ALL the images in the folder before doing the 1 month refresh? That way old files dont hang around while not being used.

<?php
$host = "127.0.0.1";
$token = "xxx";
$movies = "1";
$url = "https://$host/library/sections/$movies/recentlyAdded?X-Plex-Token=$token";
$xml = simplexml_load_file($url);
$imgurl = "https://$host/photo/:/transcode?url=";
$imgsize = "&width=280&height=420&X-Plex-Token=$token";

foreach($xml as $child) {
	$image = $child['thumb'];
	$img_url = $imgurl.$image.$imgsize;
// Time to cache the files (seconds)
define('time_to_cache', 2.628e+6);

// Create local files
// Chmod folders to 777
$local = 'cache/movies/280/' . urlencode($child['ratingKey'].'.jpg');

// Determine whether the local file is too old
if (@filemtime($local) + time_to_cache < time()) {
    // Download a fresh copy
    copy ($img_url, $local);
}
	
echo '<img width="280" height="420" src="'.$local.'">';
}
?>

If you were in Linux, I suggest making a cronjob that runs hourly or it’s up to you. So sort out your needs, create a simple checklist, and their dependencies. You’ll be spoon-fed if I’ll provide the entire solution, you’ll not learn that way (trust me).

Example Requirement:

  • :white_check_mark: Create a route that’s able to fetch the images from Plex’s API.
  • :white_check_mark: Token must not be visible in the front-end

Example Checklist:

  • Core Functionality
    • :white_check_mark: If the image’s age is < 2.628e+6s, copy the image in the local storage
    • :white_check_mark: Display the copy of the image from local storage
      • :x: Store in the database the path of the image and the time when it was last accessed.
  • Maintenance
    • :x: Create a script that will delete the image based on the time when it was last accessed.
    • :x: Register a cronjob that executes this script periodically.

TIP: It seems like you’re implementing this from scratch. just like what I have said before, there’s a cache-frameworks that can do this thing more convenient. These frameworks can purge the cache based on your needs. As you can observe, from simple needs it’s getting complex. While these cache-frameworks are prepared enough to handle simple to complex needs. A piece of friendly advice, try not to reinvent the wheel.

Thank you. I am implementing from scratch because I don’t feel like a whole framework will be much more beneficial for this usage. I only need it to do very simple things like store the image and delete them on a specific time period, which I am currently working on right now. This seems to actually be working pretty good so far.

Thanks for the tips!

1 Like