horst Posted October 5, 2013 Share Posted October 5, 2013 Hi, on a site I want to disable access to original images and only allow to access thumbnails and watermarked image variations. EDIT: A good solution for protecting original images can be found a bit down in this thread: Old content of this initial post: Spoiler To create the watermarked images I use the PiM, what creates filenames with prefix "pim_". For individual thumbnails I use the Thumbnails-Module and define the prefix like "thumb_". A simple way would be to use a htaccess file in top of the assets folder with something like this for example: The only downside is that I cannot access the original images from the admin backend. While it isn't an option to use a proxy-script from the front-end, it could be an option for the admin. Any ideas how I could access the originals when in admin backend? # deny access to all jpegs and pngs <FilesMatch "^.*\.(jpg|png)$"> Deny from all </FilesMatch> # allow access to pim_ - variations (my watermarked images) <FilesMatch "^pim_.*\.(jpg|png)$"> Allow from all </FilesMatch> # allow access to thumb_ - prefixed files (my individual thumbnails) <FilesMatch "^thumb_.*\.(jpg|png)$"> Allow from all </FilesMatch> # allow access to 100px thumbnails as used by default in PW-Admin when images-field is configured to display thumbnails <FilesMatch "^.*\.0x100\.(jpg|png)$"> Allow from all </FilesMatch> <FilesMatch "^.*\.100x0\.(jpg|png)$"> Allow from all </FilesMatch> 3 Link to comment Share on other sites More sharing options...
titanium Posted October 5, 2013 Share Posted October 5, 2013 Hi Horst, maybe you could set up a rule which takes care of the referrer, something like this? RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourdomain.com [NC] Only if the referrer equals your domain, allow access to the originals. Problem could be that your server does not use http referrers... Link to comment Share on other sites More sharing options...
horst Posted October 5, 2013 Author Share Posted October 5, 2013 Only if the referrer equals your domain, allow access to the originals. Problem could be that your server does not use http referrers... Maybe something like domain/processwire, but a referrer header could be set to anything one want, I guess. Better could be to use the REMOTE_ADDR. Does someone know how a variable for apache could be set by script? If this could be done everytime a superuser log in I could set this IP to a apache / environment variable for which access is allowed. Link to comment Share on other sites More sharing options...
BUCKHORN Posted October 8, 2013 Share Posted October 8, 2013 Private file handling is your solution. You would abstract all files from public access by doing something like... /files.php?file=myfile.jpg vs. /myfile.jpg Then in your private file handler you can check permissions and show the users the correct image according to their access level. I'm not sure if idea is native to PW. 1 Link to comment Share on other sites More sharing options...
horst Posted October 8, 2013 Author Share Posted October 8, 2013 @sshaw: what you are describing is what I have called proxy-script in my opening post. I don't want that for frontend output, because it is not needed and I want avoid overhead. All images that should have public access can be accessed directly. Others (the originals) are blocked to the public. Thats fine. The only downside is that an admin in backend also cannot access the originals. What I'm looking for is how I can define this in htaccess file: all images that are now blocked for direct access should be not served but handled by a proxy script. Link to comment Share on other sites More sharing options...
BUCKHORN Posted October 8, 2013 Share Posted October 8, 2013 This may also be useful: http://processwire.com/talk/topic/4602-flexible-downloads-using-pages/ Link to comment Share on other sites More sharing options...
BUCKHORN Posted October 8, 2013 Share Posted October 8, 2013 To do it your way, maybe use RedirectMatch in place of your first FilesMatch RedirectMatch \.(png|gif|jpg|jpeg)$ http://example.com/image_handler.php I think mod rewrite will be your ideal solution, several examples below that will get you close. Personally I'd rewrite all image requests to my proxy script, then store my allowed prefixes in an array and simply loop through the array. It's not the best solution, but it's simple and allows for some scalability. in .htaccess Redirect all images to proxy script RewriteEngine On RewriteBase / RewriteRule ^(.*)\.(jpg|png|jpeg|gif)$ watermark.php?image=$1.$2 [NC,L] in your proxy script watermark.php $prefixes[] = "thumb_"; $prefixes[] = "100x0"; foreach ($prefixes[] as $prefix) { if((substr(0,strlen($prefix)) == $prefix) xor ($user->isSuperuser())) { //return the image } else { //return a different image (maybe one that says access to this file is denied) } } Some rewrite examples that may help: Redirect requests that don't originate from the host www.example.com (stop hotlinking) RewriteEngine On RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !www.example.com [NC] RewriteRule \.(gif|jpg|png)$ /images/go-away.png [R,NC] Check for a login cookie and redirect if not logged in RewriteEngine On RewriteBase / RewriteCond %{HTTP_COOKIE} !CookieName= [NC] RewriteRule .* http://www.example.com/members/login.php [L] Link to comment Share on other sites More sharing options...
horst Posted October 16, 2013 Author Share Posted October 16, 2013 coming back to this: I have made good progress! I do not use the htaccess file in site/assets/files/ anymore but have edited the htaccess file in pw root folder. Somewhere at top of the mod_rewrite directives I have added my lines that should redirect requests to original images to a proxy-script and let others pass through: htaccess with Pim1 and PW < 2.5.11 Spoiler ... # ----------------------------------------------------------------------------------------------- # Optional: Set a rewrite base if rewrites aren't working properly on your server. # And if your site directory starts with a "~" you will most likely have to use this. # ----------------------------------------------------------------------------------------------- RewriteBase / # RewriteBase /pw/ # RewriteBase /~user/ # ----------------------------------------------------------------------------------------------- # CUSTOMSETTING : redirect original images to proxy-script - /pwimg.php?fn=... # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_FILENAME} -f RewriteCond %{REQUEST_FILENAME} (^|/)site/assets/files/(.*?)/ RewriteCond %{REQUEST_FILENAME} \.(jpg|jpeg|gif|png)$ [NC] RewriteCond %{REQUEST_FILENAME} !/pim_ #RewriteCond %{REQUEST_FILENAME} !/(thumb_|thumb2_) RewriteCond %{REQUEST_FILENAME} !.*/.*?\.([0-9]+)x([0-9]+)\.(jpg|png|jpeg|gif)$ [NC] RewriteRule ^(.*)$ pwimg.php?fn=$1 [L,QSA] # ----------------------------------------------------------------------------------------------- # Access Restrictions: Keep web users out of dirs that begin with a period # ----------------------------------------------------------------------------------------------- ... .htaccess with PW 2.5.11+ / PW 3+ # ----------------------------------------------------------------------------------------------- # CUSTOMSETTING : redirect original images to proxy-script - /pwimg.php?fn=... # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_FILENAME} -f RewriteCond %{REQUEST_FILENAME} (^|/)site/assets/files/(.*?)/ RewriteCond %{REQUEST_FILENAME} \.(jpg|jpeg|gif|png)$ [NC] RewriteCond %{REQUEST_FILENAME} !-piacrop RewriteCond %{REQUEST_FILENAME} !-piacontain RewriteCond %{REQUEST_FILENAME} !-pim2-full RewriteCond %{REQUEST_FILENAME} !-blogthumb RewriteCond %{REQUEST_FILENAME} !.*/.*?\.([0-9]+)x([0-9]+)\.(jpg|png|jpeg|gif)$ [NC] RewriteRule ^(.*)$ pwimg.php?fn=$1 [L] Now from all existing images the originals get redirected to the proxy-script and the others will delivered directly by apache. Requests to none existing imagefiles get answered by a 404. So as everything seems to work fine, the RewriteConditions could be optimized a bit. ---- pwimg.php ---- <?php // check filename $imgFilename = isset($_GET['fn']) ? preg_replace('/[^a-zA-Z0-9_\-\/\.@]/', '', $_GET['fn']) : false; $imgFilename = is_file(dirname(__FILE__) . "/$imgFilename") && is_readable(dirname(__FILE__) . "/$imgFilename") ? dirname(__FILE__) . "/$imgFilename" : false; if (false == $imgFilename) { header('HTTP/1.1 404 Not Found'); exit(2); } // check imagetype $imgType = getImageType($imgFilename); if (false == $imgType) { header('HTTP/1.1 403 Forbidden'); header('Content-type: image/jpeg'); exit(1); } // bootstrap PW require_once(dirname(__FILE__) . '/index.php'); // check user-account if (! wire('user')->hasRole('superuser|editor')) { header('HTTP/1.1 403 Forbidden'); header('Content-type: ' . $imgType); exit(1); } // collect infos $maxAge = (60 * 60 * 2); // 2 hours $imgTimestamp = filemtime($imgFilename); $imgExpiration = intval(time() + $maxAge); // create headers $imgHeaders = array(); $imgHeaders[] = 'Content-type: ' . $imgType; $imgHeaders[] = 'Content-Length: ' . filesize($imgFilename); $imgHeaders[] = 'Date: ' . gmdate('D, d M Y H:i:s',time()) . ' GMT'; $imgHeaders[] = 'Last-Modified: ' . gmdate('D, d M Y H:i:s',$imgTimestamp) . ' GMT'; $imgHeaders[] = 'Expires: ' . gmdate('D, d M Y H:i:s', $imgExpiration) . ' GMT'; $imgHeaders[] = 'pragma: cache'; $imgHeaders[] = "Cache-Control: no-transform, private, s-maxage={$maxAge}, max-age={$maxAge}"; // send headers foreach($imgHeaders as $imgHeader) header($imgHeader); // send file $errorCode = @readfile($imgFilename) === FALSE ? 1 : 0; // and exit exit($errorCode); // --- functions --- function getImageType($fn, $returnAsInteger = false) { $types1 = array(1 => 'gif', 2 => 'jpg', 3 => 'png'); $types2 = array('gif' => 1, 'jpg' => 2, 'jpeg' => 2, 'png' => 3); if (function_exists('exif_imagetype') && isset($types1[@exif_imagetype($fn)])) { $success = $types1[exif_imagetype($fn)]; } if (!isset($success) && function_exists('getimagesize')) { $info = @getimagesize($fn); if (isset($info[2]) && isset($types1[$info[2]])) { $success = $types1[$info[2]]; } } if (!isset($success)) { $extension = strtolower(pathinfo($fn, PATHINFO_EXTENSION)); if (isset($types2[$extension])) { $success = $types1[$types2[$extension]]; } } if (!isset($success)) return false; return true === $returnAsInteger ? $types2[$success] : $success; } 5 Link to comment Share on other sites More sharing options...
sirhc Posted September 19, 2017 Share Posted September 19, 2017 Hi @horst, Im looking for an exact same solution, website is showing images, but can not be accessed through going directly to the URL. I tried your solution, but also the page where the image is displayed is getting a 404 response for this image. I also have de pwimg.php as a template and page /pwimg/ instead of a 'normal' php file, is that maybe a problem? I hope you can help me with this! Thnx. Link to comment Share on other sites More sharing options...
horst Posted September 20, 2017 Author Share Posted September 20, 2017 Please read & follow my solution exactly. The way you described doesn't work & it isn't meant to do so. It describes a way to only protect the original images. Therefor you need to deny all access to them via htaccess file. In a second step, you enable access for superusers (or who ever you like) via a proxy (php) script. Nothing (!) is embedded into your PW-installation, only the htaccess file. Link to comment Share on other sites More sharing options...
sirhc Posted September 24, 2017 Share Posted September 24, 2017 Thanks for your reply. Indeed there was some misunderstanding. I got your solution working now and should be fine for now. Thanks @horst . 1 Link to comment Share on other sites More sharing options...
yorgiy Posted September 16, 2022 Share Posted September 16, 2022 Code for .htaccess file: <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_REFERER} !^http://([^.]+\.)?domain\.com/ [NC] RewriteCond %{HTTP_USER_AGENT} !(googlebot-image|msnbot|psbot|yahoo-mmcrawler) [NC] RewriteRule (^.*\.(bmp|gif|jpe?g|png)$) /watermark.php?src=$1 [L] </IfModule> Code for watermark.php PHP file: <?php header('content-type: image/jpeg'); $image = imagecreatefromjpeg($_GET['src']); $watermark = imagecreatefrompng('watermark.png'); $watermark_width = imagesx($watermark); $watermark_height = imagesy($watermark); $dest_x = imagesx($image) - $watermark_width; $dest_y = imagesy($image) - $watermark_height; imagecopymerge($image, $watermark, $dest_x - 5, 5, 0, 0, $watermark_width, $watermark_height, 80); imagejpeg($image, NULL, 85); imagedestroy($image); imagedestroy($watermark); ?> Hello, thanks for the advice. BUT .png images don't work for me Writes - The image cannot be displayed because it contains errors. What is the reason? Thank you! Link to comment Share on other sites More sharing options...
Robin S Posted July 11 Share Posted July 11 Inspired by @horst's helpful post above, here is some code for preventing guests from accessing original images that leverages more of the PW API... In .htaccess, just after "RewriteEngine On" # When original images are requested, rewrite for PHP user verification # If a matching file exists RewriteCond %{REQUEST_FILENAME} -f # And the file is within the /site/assets/files/ directory RewriteCond %{REQUEST_FILENAME} (^|/)site/assets/files/(.*?)/ # And the file extension is for an image type that we want to restrict access to RewriteCond %{REQUEST_FILENAME} \.(jpg|jpeg|gif|png)$ [NC] # And the filename portion of the path contains less than two dots (i.e. is not an image variation) RewriteCond %{REQUEST_FILENAME} !^(.+\/)?[^\/]+\.[^\/]+\.[^\/]+$ [NC] # Then rewrite to a hooked URL for user verification RewriteRule ^(.*)$ index.php?it=/original-image/ [L,QSA] In /site/ready.php // A URL hook for verifying that the user is allowed to view original images $wire->addHook('/original-image/', function($event) { $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $ext = pathinfo($path, PATHINFO_EXTENSION); $filename = $event->wire()->config->paths->root . ltrim($path, '/'); $allowed_exts = ['jpg', 'jpeg', 'png', 'gif']; // Optional: get the Pageimage and the Page it belongs to // if this affects whether the user is allowed to view the file // $pm = $event->wire()->pages(1)->filesManager; // $pageimage = $pm->getFile($filename); // $page = $pageimage->page; // Send the file if the user is allowed to view it if( // The file extension must be one of the allowed extensions in_array($ext, $allowed_exts) && // The user must be logged in $event->wire()->user->isLoggedin() && // The file must exist is_file($filename) ) { $event->wire()->files->send($filename); } // Otherwise, return a 403 Forbidden response header('HTTP/1.0 403 Forbidden'); die('403 Forbidden'); }); 5 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now