connect_error)) { header("HTTP/1.1 418 I'm a teapot"); exit; } // // connect redis // $redis = new Redis(); $port = $ini['redis']['port'] ?? 6379; $redis->connect($ini['redis']['hostname'], $port); $redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); $redis->setOption(Redis::OPT_PREFIX, ""); // // issue 404 for downloaded images if model is offline and site is specified via hideOfflineImages= in config.ini // $hideOfflineImages = $ini['webcams']['hideOfflineImages'] ?? ''; $geoBlockImages = $ini['webcams']['geoBlockImages'] ?? ''; if (!empty($hideOfflineImages) || !empty($geoBlockImages)) { $hideOfflineImages = explode(',', $hideOfflineImages); $geoBlockImages = explode(',', $geoBlockImages); if (count($hideOfflineImages) > 0 || count($geoBlockImages) > 0) { $imagesUrl = $ini['webcams']['imagesUrl']; $offlineCheck = array_reduce($hideOfflineImages, function ($r, $i) { $r[$i] = 1; return $r; } , array()); $geoCheck = array_reduce($geoBlockImages, function ($r, $i) { $r[$i] = 1; return $r; } , array()); $siteCheck = array_merge($offlineCheck, $geoCheck); // // check: $imagesUrl$siteName/*/$nickname/$index.webp // e.g: /photos/chaturbate/g/i/r/l/girlsexy/21.webp // if (preg_match("!(?$imagesUrl(?\w+)/.*/(?[\w\_\-]+)/)(.*\-)?(?\d+\.(?webp|jpg))!i", $_SERVER['REQUEST_URI'], $c)) { $c['site'] = shortSiteName($c['site']); // // fetch status of model if we need to // if (isset($siteCheck[$c['site']])) { $avos = $ini['mysql']['webcamsDatabase']; $sql = 'SELECT status, id, UNIX_TIMESTAMP() - updatedOn, blocked FROM ' . $avos . '.webcams WHERE site=' . quote($c['site']) . ' AND nickname=' . quote($c['nickname']); $res = $dbh->query($sql); $chk = $res->fetch_array(); if ($offlineCheck[$c['site']] && empty($chk) || ($chk[0] == 'o' && $chk[2] > 3600)) { // // model is offline // http_response_code(404); exit; } $model = getModel($chk[1]); if ($geoCheck[$c['site']] && !empty($chk['blocked'])) { if (function_exists('geoip_country_code_by_name')) { // // get the users 2 letter country code and check if the model has it blocked // $userCountry = \geoip_country_code_by_name($_SERVER['HTTP_X_REAL_IP']); $model['blocked'] = json_decode($model['blocked']); if (in_array(strtolower($userCountry), $model['blocked'])) { // // user is blocked // http_response_code(403); exit; } } } } // // sanity check // $_SERVER['REQUEST_URI'] = $c['path'] . $c['image']; if (strpos($_SERVER['REQUEST_URI'], '..') || !file_exists(PUB . $_SERVER['REQUEST_URI'])) { http_response_code(404); exit; } // // drop thru and output the image // } else { // // if getting here then the url doesnt match the pattern for a camsite models local thumb // or a file existing in the webroot so let avos deal with it // define('skipHideOfflineImages', 1); include TOP . 'bin/webmain.php'; exit; } } } // // convert to jpeg if webp not supported // $fullpath = PUB . $_SERVER['REQUEST_URI']; $mtime = filemtime($fullpath); $etag = sprintf('"%x-%x"', $mtime, filesize($fullpath)); if ($c['type'] == 'webp' && strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') === false) { $etagReq = (isset($_SERVER["HTTP_IF_NONE_MATCH"]) ? trim($_SERVER["HTTP_IF_NONE_MATCH"]) : false); $modSince = (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) ? strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]) : false); if ($etagReq && $etagReq === $etag) { header("HTTP/1.1 304 Not Modified"); exit; } if ($modSince && $modSince === $mtime) { header("HTTP/1.1 304 Not Modified"); exit; } $im = imagecreatefromwebp($fullpath); ob_start(); imagejpeg($im, null, 85); $jpeg = ob_get_clean(); header("Content-Type: image/jpeg"); header("Cache-Control: public, max-age=2592000"); header("Last-Modified: " . gmdate("D, d M Y H:i:s", $mtime) . " GMT"); header("ETag: $etag"); header("Content-Length: " . strlen($jpeg)); echo $jpeg; exit; } // // let the web server output the webp normally // else { if (!empty($_SERVER['X_SENDFILE_ENABLED'])) { header('Content-Type: image/webp'); header('X-Sendfile: ' . $fullpath); } else { header("Cache-Control: public, max-age=2592000"); header("Content-Type: image/$c[type]"); header('Content-Length: ' . filesize(PUB . $_SERVER['REQUEST_URI'])); header("Last-Modified: ". gmdate( "D, d M Y H:i:s", $mtime )." GMT" ); header("Etag: " . $etag); readfile(PUB . $_SERVER['REQUEST_URI']); } exit; } function quote($str) { global $dbh; return "'" . mysqli_real_escape_string($dbh, $str) . "'"; } function shortSiteName($s) { $name = str_replace( array('bongacams', 'cam4', 'chaturbate', 'flirt4free', 'stripchat', 'streamray', 'livejasmin', 'streamate', 'soulcams', 'liveflirtin', 'webcams', 'imlive', 'camsoda'), array('bc', 'c4', 'cb', 'ff', 'sc', 'sr', 'lj', 'sm', 'so', 'lf', 'wc', 'il', 'cs'), strtolower($s)); return $name; } function getModel($webcamsId, $k='', $isList=false) { global $redis; $key = "$webcamsId/p"; if ($redis->type($key) == \Redis::REDIS_NOT_FOUND) { return []; } if ($isList) { $key .= "/$k"; $ret = $redis->lRange($key, 0, -1); } elseif (empty($k)) { $ret = $redis->hGetAll($key); } else { $ret = $redis->hGet($key, $k); } return $ret; }