Jump to content

[SOLVED] 403 Forbidden when loading images from folder


jploch
 Share

Recommended Posts

Hi folks!

For a website Iam working on I need to (pre)load a huge amount of images (100-500) from a folder in assets (wich I upload via FTP).

To preload them I want to add them to the DOM inside a container, that I hide with css.
This images will be use for a frame by frame animation (that animates with scrolling) so they should be loaded parallel and if the user clicks a cancel button, the loading should be canceled. (My website is using ajax to load pages with different animations, and the loading of the second animation waits till the loading of the first animation is loaded completly, wich I want to prevent). 

I want to use ajax to do this, so I can cancel the loading with xhr.abort();

Here is my code:

var folder = '{$config->urls->assets}sequenzen/test/';

xhr = $.ajax({
    url : folder,
    success: function (data) {
        $(data).find("a").attr("href", function (i, val) {
            if( val.match(/\.(jpe?g|png|gif)$/) ) { 
                $(".preloader").append( "<img src='"+ folder + val +"'>" );
            } 
        });
    }
});

this will give me a 403 forbidden error.
After some research I found out that I have to put a .htaccess in my assets folder.
I also tried putting it in the sub folder "test", where the files are, but Iam still getting the error.

Is there anything else Iam missing? Is there a configuration in PW i have to change to do that?

Link to comment
Share on other sites

PW blocks direct access to PHP files within /site/

Alternatives are to place your PHP file outside of /site/ (e.g. in the root directory) or to use a PW template/page to respond to your AJAX request. The latter would be nice solution in this case because you could use an images field in the template to hold your animation images.

  • Like 2
Link to comment
Share on other sites

thx! I put the files in the template folder and still get a 403.
With commenting the following line in .htaccess (in root) it works:


Block access to any PHP or markup files in /site/templates/

# RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/templates($|/|/.*\.(php|html?|tpl|inc))$ [OR]

are there any security risks in doing this?

Link to comment
Share on other sites

5 minutes ago, jploch said:

thx! I put the files in the template folder and still get a 403.

The templates folder is at /site/templates/, so it's still within /site/.

I don't recommend changing any of the security restrictions in the PW htaccess file.

  • Like 1
Link to comment
Share on other sites

Because of the huge amount of images I used a file Field on a page to store the images, which is working nicely!
Now I only have the problem that I want to sort the files alphabetically/numerical.
My files are named like this: 

file_0.jpg
file_1.jpg
file_2.jpg


I have this wich is not working:

$sortetFiles = $item->sequenz_files->sort('name');
       foreach ($sortetFiles as $key => $file) {   
   echo "<img src='{$file->url}'>";
}

 

Link to comment
Share on other sites

sorry for the late response.

Iam still struggling with the sort order.
With this the images are in the wrong order:

$sortetFiles = $item->sequenz_files->sort('name');
       foreach ($sortetFiles as $key => $file) {   
   echo "<img src='{$file->url}'>";
}


Output:

<img src='0.jpg'>
<img src='1.jpg'>
<img src='10.jpg'>
<img src='100.jpg'>
<img src='101.jpg'>
<img src='102.jpg'>
.....

maybe I need to rename the Images, like 000, 001, 002, etc.?

Link to comment
Share on other sites

7 hours ago, jploch said:

maybe I need to rename the Images, like 000, 001, 002, etc.?

If you can control the naming of the images then that is an easy solution.

Otherwise you need to do natural sorting of the files array. Something like:

$files_array = $item->sequenz_files->getArray();
natsort($files_array);
// Now foreach $files_array

// And if you need the files as a Pagefiles object for some reason
$pagefiles = new Pagefiles($item);
$pagefiles->import($files_array);
// Now foreach $pagefiles

 

  • Like 2
Link to comment
Share on other sites

thanks Robin and Adrian!!
Robins solution worked for me.

Here is my final Code, with loading and sorting the files and converting them to an PageImage so that I can resize them later (if needed) :)
This Example also uses lazysizes to load the images. Maybe this helps someone:

$files_array = $item->sequenz_files->getArray();
natsort($files_array);

// And if you need the files as a Pagefiles object for some reason
$pagefiles = new Pagefiles($item);
$pagefiles->import($files_array);
// Now foreach $pagefiles
        $si = 0;
       foreach ($pagefiles as $imagefile) {
         if($imagefile->ext == 'jpg'){
         $si++;
// create a new Pageimage with the file
        $preloaderImage = new Pageimage($item->images, $imagefile->filename);
        echo "<img src='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-src='{$preloaderImage->url}' class='{$si} lazyload' />";
    }
       
}

 

  • Like 2
Link to comment
Share on other sites

On 17.11.2017 at 9:37 PM, adrian said:

PS - hope that didn't come across as though I was suggesting that is a newbie question @jploch - I would probably have referred to that old thread if I had the need once again.

no offense taken! But Iam a newbie when it comes to PHP tbh. :)   

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Similar Content

    • By Liam88
      Hi,
      I'm really struggling with this as it's something not in my wheelhouse. I'm creating a blog style page (a grid of cards) which has attributes.
      I have a snip of javascript which grabs values from checkboxes which are put into a value like the below:
      ?content=static_video&channel=facebook-ads_instagram-ads
      document.querySelector("form").onsubmit=ev=>{ ev.preventDefault(); let o={}; ev.target.querySelectorAll("[name]:checked").forEach(el=>{ (o[el.name]=o[el.name]||[]).push(el.value)}) console.log(location.pathname+"?"+ Object.entries(o).map(([v,f])=> v+"="+f.join("_")).join("&") ); document.location.href = location.pathname+"?"+ Object.entries(o).map(([v,f])=> v+"="+f.join("_")).join("&"); } As I'm currently refeshing the page on button click with those values the end result includes the location but can easily remove this.
      I then use this value in "input->get" to get the values which I then append to a find() rule. See code below:
      $selector = "template='adbank_pages',sort=published,include=all,status!=hidden"; // Get the channel and content inputs $channel = $input->get->channel; $content = $input->get->content; if($channel){ // Grab the channel string, explode into an array for checkbox checking and then replace _ with | to create or rules in the selector. $chanArray = explode("_", $channel); $chan = $channel = str_replace('_', '|', $channel); $selector = $selector .= ",ab_channels=$chan"; } if($content){ // Grab the content string, explode into an array for checkbox checking and then replace _ with | to create or rules in the selector. $contArray = explode("_", $content); $cont = $content = str_replace('_', '|', $content); $selector = $selector .= ",ab_content=$cont"; } if($input->get){ // If a valid input result $all = $pages->find($selector); } }else{ // If no input show them all $all = $page->children("template='adbank_pages',sort=-published,include=all,status!=hidden"); } $items = $all->find("limit=12"); // Limit the output and use pagination As mentioned above I currently refresh the page to adjust the $selector filter within the $all with a fallback $all if there are no results.
      I know I need to use AJAX to filter the content without refresh but I am really struggling with the set up. I have read multiple posts including the original by Ryan but still confused.
      If anyone can direct/help on this it would be appreciated.
      Thank you
    • By prestoav
      Hi there, I'm hoping someone can help here.
      I've just moved a new site from my development server account over (where the site was working fine for the client to edit content pre-launch) to the client's final hosting account and the live site is all fine. However, while most edits can be done without an issue, image uploads in admin cannot. I know this has been an issue before but, having trawled the posts about it and suggested esolutions I still can't resolve it on their host.

      PW Version: 3.0.123
      PHP version: 7.3.20
      max_execution_time 160
      max_upload_size 256M
      GD Library is enabled

      Looking at the console data it looks like the AJAX request from the image upload is getting a 403 error which is suggesting a permissions issue? First we get this on console:
       
      ?id=1169&s=1&c=1:1 Uncaught SyntaxError: Unexpected token < in JSON at position 0 Then, the AJAX request:
       
      https://*******/admin/page/edit/?&id=1169&InputfieldFileAjax=1 Gets a 403 according to Chrome Dev Tools > Network XHR. Also, the response is empty.

      Can anyone point me in the direction of the directory that deals with this and what the permission should be to allow it or indeed any other fix / area to investigate?

      Thanks so much for your help.

       
    • By ICF Church
      Hi 👋
      Anyone else having this problem?
      Requirements:
      - Repeater (matrix & normal) with mutlilanguage fields (text, textarea…) 
      - Backend language set to something other than default (ie. German) 
      Reproduce:
      - Add a new repeater Item (ajax, I found no way to possible to disable it with matrix)

      (Notice how the default language tab is active instead of the backend language…)
      - Write something into the (default language) field
      - Try to save, if field is required, this will not work. If not required, then when reloading, the content will be inside the backend language field, instead of the default language field who was (presumably) active
      Analysis:
      When  loading  a new repeater element with ajax, the default langue tab is active, but the backend language inputfield is visible (with no visual indication). When writing into the field, it will populate the backend language. When manually clicking on the default language tab (which is already active), the field will switch to the actual default language field (which is [now] empty) (that can now be populated…)
      Also Notice, the labels of the elements to be added are in default language as well instead of the translated label (images instead of Bilder)…
      ProcessWire 3.0.148, Profields 0.0.5…
      Is it my system configuration, or does anyone else have the same issue? This is a screen recording of the problem:
      Issue: https://github.com/processwire/processwire-issues/issues/1179

      Screen Recording 2020-02-25 at 14.18.31.mov
    • By gebeer
      Hello all,
      wasn't sure where to put this, so it goes in General section.
      Ryan shows a hook that we can use to mirror files on demand from live server to development environment to be up to date with the files on the server without having to download complete site/assets/files folder.
      I just implemented this but had problems getting files to load from a site in development that is secured with user/password via htaccess.
      First I tried to use WireHttp setHeader method for basic authentication like this
      function mirrorFilesfromLiveServer(HookEvent $event) { $config = $event->wire('config'); $file = $event->return; if ($event->method == 'url') { // convert url to disk path $file = $config->paths->root . substr($file, strlen($config->urls->root)); } if (!file_exists($file)) { // download file from source if it doesn't exist here $src = 'http://mydomain.com/site/assets/files/'; $url = str_replace($config->paths->files, $src, $file); $http = new WireHttp(); // basic authentication $u = 'myuser'; $pw = 'mypassword'; $http->setHeader('Authorization: Basic', base64_encode("$u:$pw")); $http->download($url, $file); } } But, unfortunately this didn't work.
      So now I am using curl to do the download. My hook function now looks like this
      function mirrorFilesfromLiveServer(HookEvent $event) { $config = $event->wire('config'); $file = $event->return; if ($event->method == 'url') { // convert url to disk path $file = $config->paths->root . substr($file, strlen($config->urls->root)); } if (!file_exists($file)) { // download file from source if it doesn't exist here $src = 'http://mydomain.com/site/assets/files/'; $fp = fopen($file, 'w+'); // init file pointer $url = str_replace($config->paths->files, $src, $file); $u = 'myuser'; $pw = 'mypassword'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_TIMEOUT, 50); // crazy high timeout just in case there are very large files curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERPWD, "$u:$pw"); // authentication curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); // authentication curl_setopt($ch, CURLOPT_FILE, $fp); // give curl the file pointer so that it can write to it curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $data = curl_exec($ch); curl_close($ch); } } Now I can load files and images from the htaccess protected development server 🙂
      If anyone knows how to get this to work with WireHttp, please let me know. Thank you.
    • By michelangelo
      Hello there,
      I am building my website, which has a dozen projects with 10 images each. Basically, I need a filtering system but built in the most efficient and user-friendly way. You can see below that the images flow sideways so being hidden, JS lazy loading was a good tool, but I just wanted to try AJAX. Is it fit for this purpose or it's more for dynamic content?
       

×
×
  • Create New...