public static function getInstance() { if (!self::$_instance) { self::$_instance = new kPlayManifestCacher(); } return self::$_instance; }
public function execute() { KExternalErrors::setResponseErrorCode(KExternalErrors::HTTP_STATUS_NOT_FOUND); $this->deliveryAttributes = new DeliveryProfileDynamicAttributes(); // Parse input parameters $this->deliveryAttributes->setSeekFromTime($this->getRequestParameter("seekFrom", -1)); if ($this->deliveryAttributes->getSeekFromTime() <= 0) { $this->deliveryAttributes->setSeekFromTime(-1); } $this->deliveryAttributes->setClipTo($this->getRequestParameter("clipTo", 0)); $this->deliveryAttributes->setPlaybackRate($this->getRequestParameter("playbackRate", 0)); $deliveryCode = $this->getRequestParameter("deliveryCode", null); $playbackContext = $this->getRequestParameter("playbackContext", null); $this->deliveryAttributes->setMediaProtocol($this->getRequestParameter("protocol", null)); if (!$this->deliveryAttributes->getMediaProtocol() || $this->deliveryAttributes->getMediaProtocol() === "null") { $this->deliveryAttributes->setMediaProtocol(PlaybackProtocol::HTTP); } $this->deliveryAttributes->setFormat($this->getRequestParameter("format")); if (!$this->deliveryAttributes->getFormat()) { $this->deliveryAttributes->setFormat(PlaybackProtocol::HTTP); } if ($this->deliveryAttributes->getFormat() == self::HDNETWORKSMIL) { $this->deliveryAttributes->setMediaProtocol(PlaybackProtocol::HTTP); } // Akamai HD doesn't support any other protocol if ($this->deliveryAttributes->getFormat() == PlaybackProtocol::AKAMAI_HDS) { if (strpos($this->deliveryAttributes->getMediaProtocol(), "http") !== 0) { $this->deliveryAttributes->setMediaProtocol(PlaybackProtocol::HTTP); } } $tags = $this->getRequestParameter("tags", null); if (!$tags) { $this->deliveryAttributes->setTags(self::getDefaultTagsByFormat($this->deliveryAttributes->getFormat())); } else { $tagsArray = explode(',', $tags); $tags = array(); foreach ($tagsArray as $tag) { $tags[] = array(trim($tag)); } $this->deliveryAttributes->setTags($tags); } $this->deliveryAttributes->setpreferredBitrate($this->getRequestParameter("preferredBitrate", null)); $this->maxBitrate = $this->getRequestParameter("maxBitrate", null); if ($this->maxBitrate && (!is_numeric($this->maxBitrate) || $this->maxBitrate <= 0)) { KExternalErrors::dieError(KExternalErrors::INVALID_MAX_BITRATE); } $this->deliveryAttributes->setStorageId($this->getRequestParameter("storageId", null)); $this->cdnHost = $this->getRequestParameter("cdnHost", null); $this->deliveryAttributes->setResponseFormat($this->getRequestParameter("responseFormat", null)); // Initialize $this->initEntry(); $this->deliveryAttributes->setEntryId($this->entryId); $this->deliveryAttributes->setUsePlayServer((bool) $this->getRequestParameter("usePlayServer") && PermissionPeer::isValidForPartner(PermissionName::FEATURE_PLAY_SERVER, $this->entry->getPartnerId())); if ($this->deliveryAttributes->getUsePlayServer()) { $this->deliveryAttributes->setPlayerConfig($this->getRequestParameter("playerConfig")); //In case request needs to be redirected to play-server we need to add the ui conf id to the manifest url as well $this->deliveryAttributes->setUiConfId($this->getRequestParameter("uiConfId")); } $this->secureEntryHelper->updateDeliveryAttributes($this->deliveryAttributes); $this->enforceEncryption(); $renderer = null; switch ($this->entry->getType()) { case entryType::MEDIA_CLIP: // VOD $renderer = $this->serveVodEntry(); break; case entryType::LIVE_STREAM: case entryType::LIVE_CHANNEL: // Live stream $renderer = $this->serveLiveEntry(); break; default: KExternalErrors::dieError(KExternalErrors::INVALID_ENTRY_TYPE); } if (!$renderer) { KExternalErrors::dieError(KExternalErrors::BAD_QUERY, 'This format is unsupported'); } $renderer->contributors = array(); $config = new kManifestContributorConfig(); $config->format = $this->deliveryAttributes->getFormat(); $config->deliveryCode = $deliveryCode; $config->storageId = $this->deliveryAttributes->getStorageId(); $config->entryId = $this->entryId; $contributors = KalturaPluginManager::getPluginInstances('IKalturaPlayManifestContributor'); foreach ($contributors as $contributor) { /* @var $contributor IKalturaPlayManifestContributor */ $renderer->contributors = array_merge($renderer->contributors, $contributor->getManifestEditors($config)); } $renderer->entryId = $this->entryId; $renderer->duration = $this->duration; if ($this->deliveryProfile) { $renderer->tokenizer = $this->deliveryProfile->getTokenizer(); } $renderer->defaultDeliveryCode = $this->entry->getPartner()->getDefaultDeliveryCode(); $renderer->lastModified = time(); // Handle caching $canCacheAccessControl = false; if (kConf::hasParam("force_caching_headers") && in_array($this->entry->getPartnerId(), kConf::get("force_caching_headers"))) { $renderer->cachingHeadersAge = 60; $renderer->forceCachingHeaders = true; } if (!$this->secureEntryHelper) { $canCacheAccessControl = true; // TODO: reconsider this if/when expired ktokens will be used } else { if (!$this->secureEntryHelper->shouldDisableCache() && !$this->secureEntryHelper->isKsAdmin() && ($this->secureEntryHelper->isKsWidget() || !$this->secureEntryHelper->hasRules())) { $canCacheAccessControl = true; } } if (!$renderer->tokenizer && $canCacheAccessControl) { // Note: kApiCache::hasExtraFields is checked in kManifestRenderers $renderer->cachingHeadersAge = 60; } if (!$this->secureEntryHelper || !$this->secureEntryHelper->shouldDisableCache()) { $cache = kPlayManifestCacher::getInstance(); $cache->storeRendererToCache($renderer); } // Output the response KExternalErrors::terminateDispatch(); $renderer->output($deliveryCode, $playbackContext); }
function checkCache() { $baseDir = "/tmp/cache_v2"; $start_time = microtime(true); $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? "https" : "http"; $host = ""; if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { $host = $_SERVER['HTTP_X_FORWARDED_HOST']; } else { if (isset($_SERVER['HTTP_HOST'])) { $host = $_SERVER['HTTP_HOST']; } } $uri = $_SERVER["REQUEST_URI"]; if (function_exists('apc_fetch')) { $url = apc_fetch("redirect-" . $protocol . $uri); if ($url) { sendCachingHeaders(60, true, time()); header("X-Kaltura:cached-dispatcher-redirect"); header("Location:{$url}"); die; } $errorHeaders = apc_fetch("exterror-{$protocol}://{$host}{$uri}"); if ($errorHeaders !== false) { sendCachingHeaders(60, true, time()); foreach ($errorHeaders as $header) { header($header); } die; } } if (strpos($uri, "/playManifest") !== false) { require_once dirname(__FILE__) . "/../apps/kaltura/lib/cache/kPlayManifestCacher.php"; $cache = kPlayManifestCacher::getInstance(); $cache->checkOrStart(); } else { if (strpos($uri, "/partnerservices2") !== false) { $params = $_GET + $_POST; unset($params['ks']); unset($params['kalsig']); $params['uri'] = $_SERVER['PATH_INFO']; $params['__protocol'] = $protocol; ksort($params); $keys = array_keys($params); $key = md5(implode("|", $params) . implode("|", $keys)); $cache_filename = "{$baseDir}/cache-{$key}"; if (file_exists($cache_filename)) { if (filemtime($cache_filename) + 600 < time()) { @unlink($cache_filename); @unlink($cache_filename . ".headers"); @unlink($cache_filename . ".log"); } else { $content_type = @file_get_contents("{$baseDir}/cache-{$key}.headers"); if ($content_type) { header("Content-Type: {$content_type}"); } $response = @file_get_contents("{$baseDir}/cache-{$key}"); if ($response) { header("Access-Control-Allow-Origin:*"); // avoid html5 xss issues if (strpos($uri, "/partnerservices2/executeplaylist") !== false) { $max_age = 60; sendCachingHeaders($max_age, true, time()); } else { sendCachingHeaders(0); } $processing_time = microtime(true) - $start_time; header("X-Kaltura:cached-dispatcher,{$key},{$processing_time}"); echo $response; die; } } } } else { if (strpos($uri, "/kwidget") !== false) { require_once dirname(__FILE__) . "/../apps/kaltura/lib/cache/kCacheManager.php"; $cache = kCacheManager::getSingleLayerCache(kCacheManager::CACHE_TYPE_PS2); if ($cache) { // check if we cached the patched swf with flashvars $uri = $protocol . $uri; $cachedResponse = $cache->get("kwidgetswf{$uri}"); if ($cachedResponse) { $max_age = 60 * 10; header("X-Kaltura:cached-dispatcher"); header("Content-Type: application/x-shockwave-flash"); sendCachingHeaders($max_age, true, time()); header("Content-Length: " . strlen($cachedResponse)); echo $cachedResponse; die; } $cachedResponse = $cache->get("kwidget{$uri}"); if ($cachedResponse) { header("X-Kaltura:cached-dispatcher"); header("Expires: Sun, 19 Nov 2000 08:52:00 GMT"); header("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma", "no-cache"); if (strpos($uri, "nowrapper") !== false) { header("Location:{$cachedResponse}"); die; } $referer = @$_SERVER['HTTP_REFERER']; $externalInterfaceDisabled = strstr($referer, "bebo.com") === false && strstr($referer, "myspace.com") === false && strstr($referer, "current.com") === false && strstr($referer, "myyearbook.com") === false && strstr($referer, "facebook.com") === false && strstr($referer, "friendster.com") === false ? "" : "&externalInterfaceDisabled=1"; $noncached_params = $externalInterfaceDisabled . "&referer=" . urlencode($referer); if (strpos($cachedResponse, "/swfparams/") > 0) { $cachedResponse = substr($cachedResponse, 0, -4) . urlencode($noncached_params) . ".swf"; } else { $cachedResponse .= $noncached_params; } header("Location:{$cachedResponse}"); die; } } } else { if (strpos($uri, "/thumbnail") !== false) { require_once dirname(__FILE__) . "/../apps/kaltura/lib/cache/kCacheManager.php"; $cache = kCacheManager::getSingleLayerCache(kCacheManager::CACHE_TYPE_PS2); if ($cache) { require_once dirname(__FILE__) . '/../apps/kaltura/lib/renderers/kRendererDumpFile.php'; $cachedResponse = $cache->get("thumb{$uri}"); if ($cachedResponse && is_array($cachedResponse)) { list($renderer, $invalidationKey, $cacheTime) = $cachedResponse; $keysStore = kCacheManager::getSingleLayerCache(kCacheManager::CACHE_TYPE_QUERY_CACHE_KEYS); if ($keysStore) { $modifiedTime = $keysStore->get($invalidationKey); if ($modifiedTime && $modifiedTime > $cacheTime) { return; // entry has changed (not necessarily the thumbnail) } } require_once dirname(__FILE__) . '/../apps/kaltura/lib/monitor/KalturaMonitorClient.php'; KalturaMonitorClient::initApiMonitor(true, 'extwidget.thumbnail', $renderer->partnerId); header("X-Kaltura:cached-dispatcher-thumb"); $renderer->output(); die; } } } else { if (strpos($uri, "/embedIframe/") !== false) { require_once dirname(__FILE__) . "/../apps/kaltura/lib/cache/kCacheManager.php"; $cache = kCacheManager::getSingleLayerCache(kCacheManager::CACHE_TYPE_PS2); if ($cache) { // check if we cached the patched swf with flashvars $cachedResponse = $cache->get("embedIframe{$uri}"); if ($cachedResponse) { header("X-Kaltura:cached-dispatcher"); sendCachingHeaders(0); header("Location:{$cachedResponse}"); die; } } } else { if (strpos($uri, "/serveFlavor/") !== false && function_exists('apc_fetch') && $_SERVER["REQUEST_METHOD"] == "GET") { require_once dirname(__FILE__) . '/../apps/kaltura/lib/renderers/kRendererDumpFile.php'; require_once dirname(__FILE__) . '/../apps/kaltura/lib/renderers/kRendererString.php'; require_once dirname(__FILE__) . '/../apps/kaltura/lib/monitor/KalturaMonitorClient.php'; require_once dirname(__FILE__) . '/../apps/kaltura/lib/request/kIpAddressUtils.php'; $host = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST']; $cacheKey = 'dumpFile-' . kIpAddressUtils::isInternalIp($_SERVER['REMOTE_ADDR']) . '-' . $host . $uri; $renderer = apc_fetch($cacheKey); if ($renderer) { KalturaMonitorClient::initApiMonitor(true, 'extwidget.serveFlavor', $renderer->partnerId); header("X-Kaltura:cached-dispatcher"); $renderer->output(); die; } } } } } } } }
function checkCache() { $baseDir = "/tmp/cache_v2"; $start_time = microtime(true); $uri = $_SERVER["REQUEST_URI"]; $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? "https" : "http"; if (function_exists('apc_fetch')) { $url = apc_fetch("redirect-" . $protocol . $_SERVER["REQUEST_URI"]); if ($url) { $max_age = 60; header("Cache-Control: private, max-age={$max_age}, max-stale=0"); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $max_age) . ' GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); header("X-Kaltura:cached-dispatcher-redirect"); header("Location:{$url}"); die; } } if (strpos($uri, "/playManifest") !== false) { require_once dirname(__FILE__) . "/../apps/kaltura/lib/cache/kPlayManifestCacher.php"; $cache = kPlayManifestCacher::getInstance(); $cache->checkOrStart(); } if (strpos($uri, "/partnerservices2") !== false) { $params = $_GET + $_POST; unset($params['ks']); unset($params['kalsig']); $params['uri'] = $_SERVER['PATH_INFO']; ksort($params); $keys = array_keys($params); $key = md5(implode("|", $params) . implode("|", $keys)); $cache_filename = "{$baseDir}/cache-{$key}"; if (file_exists($cache_filename)) { if (filemtime($cache_filename) + 600 < time()) { @unlink($cache_filename); @unlink($cache_filename . ".headers"); @unlink($cache_filename . ".log"); } else { $content_type = @file_get_contents("{$baseDir}/cache-{$key}.headers"); if ($content_type) { header("Content-Type: {$content_type}"); } $response = @file_get_contents("{$baseDir}/cache-{$key}"); if ($response) { header("Access-Control-Allow-Origin:*"); // avoid html5 xss issues if (strpos($uri, "/partnerservices2/executeplaylist") !== false) { $max_age = 60; header("Cache-Control: private, max-age={$max_age}, max-stale=0"); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $max_age) . 'GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT'); } else { header("Expires: Sun, 19 Nov 2000 08:52:00 GMT"); header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); } $processing_time = microtime(true) - $start_time; header("X-Kaltura:cached-dispatcher,{$key},{$processing_time}"); echo $response; die; } } } } if (strpos($uri, "/kwidget") !== false) { if (!function_exists('memcache_connect')) { return; } $cache = new Memcache(); $res = @$cache->connect("localhost", "11211"); if ($res) { // check if we cached the patched swf with flashvars $uri = $protocol . $uri; $cachedResponse = $cache->get("kwidgetswf{$uri}"); if ($cachedResponse) { $max_age = 60 * 10; header("X-Kaltura:cached-dispatcher"); header("Content-Type: application/x-shockwave-flash"); header("Cache-Control: private, max-age={$max_age} max-stale=0"); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $max_age) . 'GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT'); header("Content-Length: " . strlen($cachedResponse)); echo $cachedResponse; die; } $cachedResponse = $cache->get("kwidget{$uri}"); if ($cachedResponse) { // set our uv cookie $uv_cookie = @$_COOKIE['uv']; if (strlen($uv_cookie) != 35) { $uv_cookie = "uv_" . md5(uniqid(rand(), true)); } setrawcookie('uv', $uv_cookie, time() + 3600 * 24 * 365, '/'); header("X-Kaltura:cached-dispatcher"); header("Expires: Sun, 19 Nov 2000 08:52:00 GMT"); header("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma", "no-cache"); if (strpos($uri, "nowrapper") !== false) { header("Location:{$cachedResponse}"); die; } $referer = @$_SERVER['HTTP_REFERER']; $externalInterfaceDisabled = strstr($referer, "bebo.com") === false && strstr($referer, "myspace.com") === false && strstr($referer, "current.com") === false && strstr($referer, "myyearbook.com") === false && strstr($referer, "facebook.com") === false && strstr($referer, "friendster.com") === false ? "" : "&externalInterfaceDisabled=1"; $noncached_params = $externalInterfaceDisabled . "&referer=" . urlencode($referer); if (strpos($cachedResponse, "/swfparams/") > 0) { $cachedResponse = substr($cachedResponse, 0, -4) . urlencode($noncached_params) . ".swf"; } else { $cachedResponse .= $noncached_params; } header("Location:{$cachedResponse}"); die; } } } else { if (strpos($uri, "/thumbnail") !== false) { if (!function_exists('memcache_connect')) { return; } $cache = new Memcache(); $res = @$cache->connect("localhost", "11211"); if ($res) { $file_name = $cache->get("thumb{$uri}"); if ($file_name && file_exists($file_name)) { $ext = pathinfo($file_name, PATHINFO_EXTENSION); if ($ext == "jpg") { $content_type = "image/jpeg"; } else { $content_type = "image/{$ext}"; } $total_length = filesize($file_name); $max_age = 8640000; header("X-Kaltura:cached-dispatcher-thumb"); header("Cache-Control: public, max-age={$max_age} max-stale=0"); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $max_age) . 'GMT'); header('Last-Modified: Sun, 19 Nov 2000 08:52:00 GMT'); header("Content-Length: {$total_length} "); header("Pragma:"); header("Content-Type: {$content_type}"); $chunk_size = 100000; $fh = fopen($file_name, "rb"); if ($fh) { $pos = 0; while ($total_length >= 0) { $content = fread($fh, $chunk_size); echo $content; $total_length -= $chunk_size; } fclose($fh); } die; } } } } }
public function execute() { $this->seekFrom = $this->getRequestParameter("seekFrom", -1); if ($this->seekFrom <= 0) { $this->seekFrom = -1; } $this->clipTo = $this->getRequestParameter("clipTo", 0); $this->deliveryCode = $this->getRequestParameter("deliveryCode", null); $playbackContext = $this->getRequestParameter("playbackContext", null); $this->protocol = $this->getRequestParameter("protocol", null); if (!$this->protocol || $this->protocol === "null") { $this->protocol = StorageProfile::PLAY_FORMAT_HTTP; } $this->format = $this->getRequestParameter("format"); if (!$this->format) { $this->format = StorageProfile::PLAY_FORMAT_HTTP; } $this->tags = $this->getRequestParameter("tags", null); if (!$this->tags) { switch ($this->format) { case StorageProfile::PLAY_FORMAT_SILVER_LIGHT: $this->tags = array(array(assetParams::TAG_SLWEB)); break; case StorageProfile::PLAY_FORMAT_APPLE_HTTP: case StorageProfile::PLAY_FORMAT_HDS: $this->tags = array(array(assetParams::TAG_APPLEMBR), array('ipadnew', 'iphonenew'), array('ipad', 'iphone')); break; default: $this->tags = array(array(assetParams::TAG_MBR), array(assetParams::TAG_WEB)); } } else { $this->tags = array(array($this->tags)); } $this->cdnHost = $this->getRequestParameter("cdnHost", null); $this->preferredBitrate = $this->getRequestParameter("preferredBitrate", null); $this->maxBitrate = $this->getRequestParameter("maxBitrate", null); if ($this->maxBitrate && (!is_numeric($this->maxBitrate) || $this->maxBitrate <= 0)) { KExternalErrors::dieError(KExternalErrors::INVALID_MAX_BITRATE); } $this->initEntry(); $this->initFlavorIds(); $this->storageId = $this->getRequestParameter("storageId", null); $this->validateStorageId(); $partner = $this->entry->getPartner(); if (!$this->cdnHost || $partner->getForceCdnHost()) { $this->cdnHost = myPartnerUtils::getCdnHost($this->entry->getPartnerId(), $this->protocol); } $playbackParams = array(); if (kConf::hasMap("optimized_playback")) { $partnerId = $this->entry->getPartnerId(); $optimizedPlayback = kConf::getMap("optimized_playback"); if (array_key_exists($partnerId, $optimizedPlayback)) { $playbackParams = $optimizedPlayback[$partnerId]; } } if (array_key_exists('enforce_encryption', $playbackParams) && $playbackParams['enforce_encryption']) { if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on') { KExternalErrors::dieError(KExternalErrors::ACCESS_CONTROL_RESTRICTED, 'unencrypted manifest request - forbidden'); } if (strtolower($this->protocol) != 'https') { KExternalErrors::dieError(KExternalErrors::ACCESS_CONTROL_RESTRICTED, 'unencrypted playback protocol - forbidden'); } } $renderer = null; switch ($this->format) { case StorageProfile::PLAY_FORMAT_HTTP: $renderer = $this->serveHttp(); break; case StorageProfile::PLAY_FORMAT_RTMP: $renderer = $this->serveRtmp(); break; case StorageProfile::PLAY_FORMAT_SILVER_LIGHT: $renderer = $this->serveSilverLight(); break; case StorageProfile::PLAY_FORMAT_APPLE_HTTP: $renderer = $this->serveAppleHttp(); break; case StorageProfile::PLAY_FORMAT_HDS: $renderer = $this->serveHds(); break; case "url": $this->format = "http"; // build url for an http delivery $renderer = $this->serveUrl(); break; case "rtsp": $renderer = $this->serveRtsp(); break; case "hdnetworksmil": $renderer = $this->serveHDNetworkSmil(); break; case "hdnetwork": $renderer = $this->serveHDNetwork(); break; case "hdnetworkmanifest": $renderer = $this->serveHDNetworkManifest(); break; } if (!$renderer) { KExternalErrors::dieError(KExternalErrors::BAD_QUERY, 'This format is unsupported'); } $canCacheAccessControl = false; if (!$this->secureEntryHelper) { $canCacheAccessControl = true; // TODO: reconsider this if/when expired ktokens will be used } else { if (!$this->secureEntryHelper->shouldDisableCache() && !$this->secureEntryHelper->isKsAdmin() && ($this->secureEntryHelper->isKsWidget() || !$this->secureEntryHelper->hasRules())) { $canCacheAccessControl = true; } } if (!$renderer->tokenizer && $canCacheAccessControl) { // Note: kApiCache::hasExtraFields is checked in kManifestRenderers $renderer->cachingHeadersAge = 60; } if (!$this->secureEntryHelper || !$this->secureEntryHelper->shouldDisableCache()) { $cache = kPlayManifestCacher::getInstance(); $cache->storeCache($renderer); } $renderer->output($playbackContext); }